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中。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值