当前位置: 首页 > article >正文

JVM面试真题总结(十)

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

在这里插入图片描述

是否所有对象都分配在堆内存上?

在Java中,对象主要是在堆上分配的。

堆是JVM中专门用于动态分配内存的区域,所有的对象实例以及数组都需要在堆上分配。

  • 当我们创建一个新的对象实例时,JVM会在堆上为这个新的对象分配内存。

然而,要注意的是,虽然对象实例本身是在堆上分配的,但是对这些对象的引用通常是在栈上分配的。

  • 比如,当我们在一个方法中创建一个新的对象时,这个对象的引用通常会被存储在当前线程的栈帧中。

除此之外,也要注意到Java 8引入的元空间(Metaspace)来替代永久代(PermGen)。

  • 类的元数据(如类的名字,字段,方法等)存储在元空间,而不是堆内存中。

另外,Java HotSpot虚拟机还引入了一种叫做逃逸分析的优化技术。

通过这种技术,JVM可以判断出一个新创建的对象的引用是否会逃逸出当前方法或者当前线程。

如果JVM通过逃逸分析判断出一个对象的引用不会逃逸出当前方法,那么这个对象可能会被优化为在栈上分配

  • 而不是在堆上分配,这种技术可以有效减少垃圾收集的压力。

但这是一种优化技术,并不是通常情况下的行为。

什么是直接内存?

直接内存并不是Java虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。

  • 它是在Java堆外分配的内存,直接受操作系统管理。

Java中的ByteBuffer类可以用来创建直接内存。

当我们调用ByteBufferallocateDirect方法时,Java虚拟机会调用本地方法,在堆外分配一块内存。

  • 这块内存不受Java垃圾收集器管理,所以在使用完后需要手动释放。

使用直接内存的主要好处是可以减少在Java堆和原生堆之间复制数据的次数。

  • 特别是在进行网络通信或者文件操作时,数据通常需要从Java堆复制到原生堆
    • 然后再从原生堆复制到操作系统的内核缓冲区。
    • 如果使用直接内存,数据就可以直接在原生堆中操作,无需在Java堆和原生堆之间进行复制。

但是,直接内存的分配和回收都比较昂贵

  • 所以只有在确实需要通过减少内存复制来提高性能的地方,才使用直接内存。

  • 另外,由于直接内存不受Java垃圾收集器管理,如果不正确地使用它,可能会造成内存泄漏。

详细描述JVM加载字节码文件的过程

JVM加载字节码文件的过程通常被称为类加载过程,主要包括以下几个步骤:

加载(Loading):

这是类加载过程的第一步,主要完成了以下三件事情:

  • 通过全类名获取定义该类的二进制字节流。
  • 将字节流代表的静态存储结构转化为方法区的运行时数据结构。
  • 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

链接(Linking):

链接阶段主要将原始的类文件字节码转化为可以被JVM直接使用的形式。

  • 验证(Verification):
    • 确保被加载的类的信息符合JVM规范,没有安全方面的问题。
  • 准备(Preparation):
    • 为类的静态变量分配内存,并将其初始化为默认值。
  • 解析(Resolution):
    • 将类的二进制数据中的符号引用替换为直接引用。

初始化(Initialization):

这个阶段主要执行类中定义的Java程序代码。

JVM将会根据类的字节码中的指令,对类进行初始化。

使用(Using):

程序使用该类进行各种操作。

卸载(Unloading):

当该类不再需要,类加载器将其卸载,回收内存。

这个过程是由类加载器(ClassLoader)执行的。

Java中有三种内置的类加载器:

  • 引导类加载器(Bootstrap ClassLoader
    • 扩展类加载器(Extension ClassLoader)和应用类加载器(Application ClassLoader)。
  • 我们也可以自定义类加载器,通过继承java.lang.ClassLoader类并覆盖它的方法来实现。

类加载器的类型有哪些?

Java的类加载器大体可以分为以下四种:

引导类加载器(Bootstrap ClassLoader):

  • 这是最顶层的类加载器,主要负责加载Java的核心类库,这些类库是Java运行时最基础的类库
    • rt.jar、resources.jar、charsets.jar等。
    • 引导类加载器是C++实现的,它并不继承自java.lang.ClassLoader

扩展类加载器(Extension ClassLoader):

  • 这是引导类加载器的子类,负责加载Java的扩展类库,如jce.jar、jsse.jar、jfr.jar
    • 以及java.ext.dirs路径下的jar包。
    • 扩展类加载器是Java实现的。

应用类加载器(Application ClassLoader):

  • 也被称为系统类加载器,是扩展类加载器的子类,负责加载用户类路径(ClassPath)上的类库。
    • 这个是程序默认的类加载器,也是ClassLoader.getSystemClassLoader()方法的返回值。

自定义类加载器(User ClassLoader):

  • Java也允许我们自定义类加载器
    • 我们可以继承java.lang.ClassLoader类,并覆盖其findClass()方法来自定义类加载器。
    • 自定义类加载器可以用于一些特殊的场景
    • 比如需要从网络、数据库加载类,或者需要对类进行加密和解密等。

类加载器的主要作用是加载Java类到JVM中。

当程序需要使用某个类时,如果这个类还没有被加载到内存中,那么系统就会通过类加载器来加载这个类。

一旦类被加载到内存中,就可以创建这个类的对象,或者调用这个类的静态方法和静态字段。


http://www.kler.cn/news/305026.html

相关文章:

  • HarmonyOS开发者基础认证试题
  • CSP-J阅读程序专题第二题 - 2
  • 回溯——12.N皇后
  • 源码编译安装python3.12没有ssl模块,python3.12 ModuleNotFoundError: No module named ‘_ssl‘
  • 【H2O2|全栈】关于CSS(2)CSS基础(二)
  • Android 设备的独立环境
  • 在Pycharm中使用GitHub
  • JavaScript 中的异步任务、同步任务、宏任务与微任务
  • Vue3 Day1Day2-Vue3优势ref、reactive函数
  • 基于STM32设计的智能家庭防盗系统(华为云IOT)(224)
  • 速盾:你知道高防 IP 和高防 CDN 的区别吗?
  • 846. 树的重心
  • git-fork操作指南
  • Qt_信号与槽
  • 【洛谷】P9752 [CSP-S 2023] 密码锁
  • C++:opencv生成结构元素用于膨胀腐蚀等cv::getStructuringElement
  • 中级练习[6]:Hive SQL订单配送与用户社交行为分析
  • Windows 环境下安装、使用、nodeJs 连接 TiDB 数据库
  • 使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用
  • 外观模式详解:如何为复杂系统构建简洁的接口
  • UE4_后期处理六—夜视仪、扫描线
  • 瑞芯微RK3568鸿蒙开发板OpenHarmony系统修改cfg文件权限方法
  • 如何提升RAG检索的准确率及答案的完整性?
  • Qt与Udp
  • git update-ref
  • 网络安全 DVWA通关指南 DVWA SQL Injection (Blind SQL盲注)
  • 【iOS】单例模式
  • 使用 PyTorch 构建 MNIST 手写数字识别模型
  • 基于单片机的水情监测站设计
  • TDengine 与飞腾腾锐 D2000 完成兼容互认证,推动国产软硬件深度融合