JVM?
Java虚拟机,可以理解为Java程序的运行环境,可以执行Java字节码(Java bytecode)并提供了内存管理、垃圾回收、线程管理等功能
java内存区域划分?每块内存中都对应什么?
- 方法区:类的结构信息、常量池、静态变量、即时编译器编译后的代码等。
- 堆:对象实例(堆分为新生代和老生代,新生代对象变化频繁,经常触发GC,老生代变化较缓)。
- 虚拟机栈:每个方法的局部变量表、操作数栈、动态链接、方法出口等。
- 本地方法栈:本地方法的调用和执行状态。
- 程序计数器:当前线程执行的字节码指令地址。
总结:
新生代又分为Eden空间、Survivor空间,Survivor空间又有Survivor1和Survivor2,大部分对象首先被分配到新生代的Eden空间,经过一次垃圾回收后,如果存活则进入Survivor空间,经过多次回收后仍然存活的对象会被晋升到老年代。
一个类的加载流程?
加载(Loading):加载是类加载的第一阶段。在此阶段,类加载器通过类的全限定名(Fully Qualified Name)来查找并读取类的字节码文件(通常是以.class文件形式存储的)。类加载器可以从文件系统、网络、JAR包等位置获取字节码文件的二进制数据,并将其转换成内部数据结构表示的类。
验证(Verification):验证是类加载的第二阶段。在此阶段,虚拟机会对字节码进行合法性校验,确保字节码符合Java语言规范和虚拟机规范,避免安全漏洞和不合规的字节码引起的问题。
准备(Preparation):准备是类加载的第三阶段。在此阶段,虚拟机为类的静态变量分配内存,并设置默认初始值(零值),例如0、null等。这些静态变量通常存储在方法区中。
解析(Resolution):解析是类加载的第四阶段。在此阶段,虚拟机会将类中的符号引用转换为直接引用。符号引用指向类、字段、方法等在运行时才能确定具体内存地址的符号,而直接引用则直接指向内存中的对象、方法等。
初始化(Initialization):初始化是类加载的最后一阶段。在此阶段,虚拟机会执行类的初始化代码,包括静态变量赋值和静态代码块的执行。初始化时,按照静态变量定义的顺序依次执行,并且是线程安全的。初始化完成后,类被标记为已初始化,可以使用了。
垃圾回收算法有哪些?
- 标记清除法,首先,从根对象(gc root)开始标记所有可达对象,即从根对象出发遍历对象图,并给可达对象打上标记。然后,在清除阶段,遍历整个堆内存,将未标记的对象进行回收。标记-清除算法可以解决循环引用的问题,但容易产生内存碎片。
- 标记整理法,为了解决复制和清除算法的缺陷,在回收垃圾后会向内存—边整理对象,这会栖牲比较多的性能。
- 复制算法,该算法将内存分为两个区域,一半为活动区(From Space),一半为空闲区(To Space)。在垃圾回收过程中,将活动区中存活的对象复制到空闲区,并更新引用关系。最后,交换两个区域的角色,即将空闲区变为活动区,原活动区变为空闲区。该算法简单高效,但对内存利用率较低。
- 分代算法,通常将新创建的对象放入新生代(Young Generation),经过多次垃圾回收仍存活的对象会被晋升到老年代(Old Generation)。新生代采用复制算法,而老年代采用标记整理算法。这样能够根据对象的特性进行不同的优化,提高垃圾回收的效率。
总结:
标记删除,实现简单,但是删除过后容易产生内存碎片。复制算法,解决了内存碎片的问题,同是也是比较高效的回收算法,但是使用了比较高昂的内存空间作为代价。标记整理算法,为了解决复制和清除算法的缺陷,在回收垃圾后会向内存—边整理对象,这会栖牲比较多的性能。分代算法是把内存空间划分为不同代,新生代和老年代。每个代因其功能职责不同采用不同的垃圾回收算法,新生代因为对象朝生夕死所以采用复制算法,提高回收效率,老年代则采用标记整理。
什么是双亲委派机制?
当一个类加载器需要加载某个类时,它首先会将该请求委派给它的父加载器,只有在父加载器无法完成加载时,才由子加载器自行加载。
总结:
通过双亲委派机制,Java类加载器构成了一个层次结构,形成了一种从上到下的类加载器链。这种结构保证了类的一致性和稳定性,并且可以防止用户自定义的类库覆盖Java核心类库的安全问题。当一个类被加载后,它会由加载它的类加载器和它的类本身共同确定其在虚拟机中的唯一性。
如何主动触发垃圾回收?
System.gc()
方法是一个静态方法,它会通知JVM进行垃圾回收操作。实际上,这只是一个建议,具体是否进行垃圾回收还是取决于JVM的内部策略。JVM可能会选择立即执行垃圾回收,也可能会忽略该建议。另外,Java虚拟机提供了一个
Runtime
类,它有一个gc()
方法,与System.gc()
具有相同的功能。你可以使用Runtime.getRuntime().gc()
来调用垃圾回收。需要注意的是,频繁地手动触发垃圾回收并不是一个好的做法。JVM通常会根据当前系统资源的使用情况和垃圾回收算法的策略自动进行垃圾回收,手动触发垃圾回收可能会导致不必要的性能开销。通常情况下,我们应该信任JVM的垃圾回收机制,并正确管理对象的生命周期,让JVM自己来决定何时进行垃圾回收。
什么是young GC?什么是full GC?什么是stw?
young GC 就是新生代的垃圾回收,比较频繁,full GC是老生代的垃圾回收,效率比较低,并且会触发 stw,stw就是除了垃圾回收这个线程其他线程都停止。