JVM问题
Java中有哪些类加载器?
在Java中,有以下几种常见的类加载器:
启动类加载器(Bootstrap Class Loader):也称为根加载器,是Java虚拟机的一部分,它负责加载Java核心库(如rt.jar)和其他支持文件,它是用本地代码实现的,不继承自java.lang.ClassLoader。
扩展类加载器(Extension Class Loader):也称为扩展加载器,它是用来加载Java的扩展库(如javax扩展包)的。它是由sun.misc.Launcher$ExtClassLoader实现的,它的父加载器是启动类加载器。
应用程序类加载器(Application Class Loader):也称为系统类加载器,它负责加载应用程序的类路径上指定的类库。它是由sun.misc.Launcher$AppClassLoader实现的,它的父加载器是扩展类加载器。
除了上述三种常见的类加载器外,还可以通过编写自定义的类加载器来实现特定的加载需求。自定义类加载器可以继承自java.lang.ClassLoader类,并重写其中的方法来定义自己的加载逻辑。
需要注意的是,类加载器遵循双亲委派模型(Parent Delegation Model),即当一个类加载器收到加载请求时,它首先将加载任务委派给父加载器,只有当父加载器无法加载时,才由当前加载器自己来完成加载。这个模型可以保证类的唯一性和安全性。
JVM有哪些垃圾回收算法。
Java虚拟机(JVM)中有以下几种常见的垃圾回收算法:
标记-清除算法(Mark and Sweep):标记-清除算法分为两个阶段,首先标记出所有活动对象,然后清除未标记的对象。这种算法会产生内存碎片,影响内存的连续分配。
复制算法(Copying):复制算法将可用内存划分为大小相等的两个区域,每次只使用其中的一个区域。当当前区域的对象存活时,将存活对象复制到另一个区域,然后清除当前区域中的所有对象。这种算法消耗了一部分内存空间,但是不会产生内存碎片,适用于存活对象较少的场景。
标记-整理算法(Mark and Compact):标记-整理算法也是分为两个阶段,首先标记出所有活动对象,然后将所有活动对象向一端移动,然后清理掉边界以外的内存。这种算法可以解决标记-清除算法产生的内存碎片问题。
分代收集算法(Generational Collection):分代收集算法根据对象的存活周期将堆内存分为不同的代(Generation),通常分为年轻代(Young Generation)和老年代(Old Generation)。年轻代中的对象存活时间较短,采用复制算法进行垃圾回收;老年代中的对象存活时间较长,采用标记-整理算法进行垃圾回收。这种算法充分利用了对象存活时间的特点,提高了垃圾回收的效率。
除了上述算法外,还有一些特定的垃圾回收算法,如增量式收集算法(Incremental Collection)、并发收集算法(Concurrent Collection)等。这些算法都有各自的特点和适用场景,Java虚拟机会根据具体的情况选择合适的垃圾回收算法来进行内存管理。
JVM有几个区域?
Java虚拟机(JVM)可以划分为以下几个主要的区域:
程序计数器(Program Counter):程序计数器是一块较小的内存区域,它记录了当前线程执行的字节码指令的地址或索引。每个线程都有独立的程序计数器,用于支持线程切换、方法调用和返回等操作。
Java虚拟机栈(JVM Stack):Java虚拟机栈用于存储方法调用和局部变量。每个线程在执行Java方法时都会创建对应的栈帧,栈帧包含了方法的局部变量表、操作数栈、动态链接、方法出口等信息。虚拟机栈可以动态地增长或缩小,具体取决于实现。
本地方法栈(Native Method Stack):本地方法栈类似于虚拟机栈,但是它用于支持本地方法(Native Method)的调用。本地方法是用其他编程语言(如C或C++)编写的,需要通过本地方法接口(JNI)与Java代码进行交互。
Java堆(Java Heap):Java堆是Java虚拟机管理的最大的一块内存区域。它用于存储对象实例和数组。Java堆是所有线程共享的区域,被所有线程共同使用。
方法区(Method Area):方法区用于存储类的结构信息、常量、静态变量和编译后的代码等。方法区也是所有线程共享的区域。在较早的JVM实现中,方法区被实现为永久代(Permanent Generation),但在JDK 8及以后的版本中,永久代被元空间(Metaspace)所取代。
除了上述主要区域,还有一些其他的辅助区域,例如运行时常量池(Runtime Constant Pool)和直接内存(Direct Memory)。这些区域在Java虚拟机的内存布局中起到辅助的作用。
JVM有哪些是线程共享区。
在Java虚拟机(JVM)中,存在以下几个线程共享的区域:
堆(Heap):堆是Java虚拟机中最大的内存区域,用于存储对象实例和数组。所有线程共享堆内存,堆中的对象可以被多个线程访问和操作。
方法区(Method Area):方法区用于存储类的结构信息、常量、静态变量和编译后的代码等。它也是所有线程共享的区域。
运行时常量池(Runtime Constant Pool):运行时常量池是方法区的一部分,用于存储编译时期生成的各种字面量和符号引用。它也是所有线程共享的。
类数据共享区(Class Data Sharing,CDS):CDS 是一种特殊的线程共享区域,它允许多个Java虚拟机进程共享类的元数据和字节码信息,从而减少内存占用和启动时间。CDS 在JDK 5及以后的版本中引入。
除了上述线程共享的区域,Java虚拟机还有一些线程私有的区域,例如程序计数器(Program Counter,PC Register)、虚拟机栈(VM Stack)和本地方法栈(Native Method Stack)。这些区域在每个线程中都有独立的副本,用于支持线程的执行和方法调用。