JVM的一些问题
一、 JVM的内存划分
二、 JAVA类加载的全过程是怎样的?什么是双亲委派机制?有什么作用?一个对象从加载到JVM,再到被GC清除,都经历了什么过程?
JAVA的类加载器: AppClassLoader->ExtClassloader -> BootStrap Classloader
每种类加载器都有他自己的加载目录
JAVA中的类加载器:AppClassLoader , ExtClassLoader -> URLClassLoader -> SecureClassLoader -> ClassLoader
每个类加载器对他加载过的类,都是有一个缓存的
双亲委派模型:向上委托查找,向下委托加载。 作用:保护Java的类不会被应用程序覆盖
类加载过程:
类加载过程: 加载 -> 连接 -> 初始化
加载: 把Java的字节码数据加载到JVM内存当中,并映射成JVM认可的数据结构。
连接:分为三个小的阶段: 1、 验证:检查加载到的字节信息是否符合JVM规则
2、 准备:创建类或者接口的静态变量,并赋初始值 半初始化状态
3、 解析:把符号引用转化为直接引用
初始化:
三、一个对象从加载到JVM,再到被GC清除都经历了什么
- 用户创建一个对象,JVM首先需要到方法去找对象的类型信息,然后再创建对象。
- JVM要实例化一个对象,首先要在堆当中先创建一个对象。->半初始化状态
- 对象首先会分配在堆内存中新生代的Eden。然后经过一次Minor GC,如果对象存活,就会进入S区。在后续的每次GC中,如果对象一直存活,就会在S区来回拷贝,每移动一次,年龄加1。->多大年龄才会移入老年代?年龄最大15,超过一定年龄后,对象转入老年代。
- 当方法执行结束后,栈中的指针会先移除掉。
- 堆中的对象,经过Full GC,就会被标记为垃圾,然后被GC线程清理掉。
怎么确定一个对象到底是不是垃圾?什么是Gc root
有两种定位垃圾的方式:
引用计数:这种方式是给堆内存当中的每个对象记录一个引用个数。引用个数为0的就认为是垃圾。这是早期JDK中使用的方式。引用计数无法解决循环引用的问题。
根可达算法:这种方式是在内存中,从引用根对象向下一直找引用,找不到的对象就是垃圾。
哪些是GC Root?
Stack -> JVM Stack , Native Stack ,Class类,run-time constant pool 常量池, static reference 静态变量。
四、 JVM有哪些垃圾回收算法
MarkSweep 标记清除算法
这个算法分为两个阶段,标记阶段:把垃圾内存标记出来 清除阶段:直接将垃圾内存回收。
这种算法是比较简单的,但是有个严重的问题,会产生大量的内存碎片
Coping 拷贝算法
为了解决标记清除算法的内存碎片问题,就产生了拷贝算法。拷贝算法将内存氛围大小相等的两半,每次只使用其中一半。垃圾回收时,将当前这一块的存活对象全部拷贝到另一半,然后当前这一半就可以直接清除。
这种算法没有内存碎片,但是他的问题就在于浪费空间。而且,他的效率跟存活的对象个数有关。
MarkCompack 标记压缩算法
为了解决拷贝算法的缺陷,就引出了标记压缩算法。这种熟饭在标记阶段跟标记清除算法是一样的,但是在完成标记之后,不是直接清理垃圾内存,而是将存活对象往一端移动,然后将端边界以外的所有内存直接清除。
这三种算法各种利弊,各有适合的场景。
五、JVM有哪些垃圾回收器?他们都是怎么工作的?什么是STW?他们都发生在哪些阶段?什么是三色标记?如何解决错标记和漏标记的问题?为什么要设计那么多的垃圾回收器?
STW: Stop-The_World 是在垃圾回收算法执行过程当中,需要将JVM内存冻结的一种状态。在STW状态下啊,JAVA的所有线程都是停止执行的,GC线程除外,native方法可以执行,但是不能与JVM交互。GC各种算法优化的 重点,就是减少StW,同时这也是JVM调优的重点。
JVM的垃圾回收器:
serial 串行
整体过程比较简单,就像踢足球一样,需要GC时,直接暂停,GC完了再继续。
这个垃圾回收器,是早期的垃圾回收器,只有一个线程执行GC。在多CPU架构下,性能就会下降严重。只适用于几十兆的内存空间。
Parallel并行
在串行基础上,增加多线程GC。PS+PO这种组合是JDK1.8默认的垃圾回收器。在多CPU的架构下,性能会比Serial高很多。
CMS Concurrent Mark Sweep
核心思想,就是将STW大三,让一部分线程与用户线程并发执行。整个GC过程分为4个阶段
- 初始标记阶段:STW 只标记处根对象直接引用的对象。
- 并发标记:继续标记其他对象,与应用城西是并发执行。
- 重新标记:STW对并发执行阶段的对象进行重新标记。
- 并发清除:并行。将产生的垃圾清除。清除过程中,应用程序又会不断产生新的垃圾,叫做浮动垃圾。这些垃圾就要留到下一次GC过程中清除。
G1 Garbage First
他的内存模型是实际不分代,但是逻辑上是分代的。对于堆内存就不在分老年代和新生代,而是划分为一个一个的小内存块,叫做Region。每个Region可以隶属于不同的分代
GC分为4个阶段:
第一:初始标记 标记出 GCRoot直接引用的对象。STW
第二:标记Region,通过RSet标记出上一个阶段标记的Region引用到的Old区Region。
第三:并发标记阶段:跟CMS的步骤基本一致。只是遍历的范围不再是整个Old区,而只需要遍历第二步标记出来的Region。
第四:重新标记:跟CMS中的重新标记过程是差不多的。
第五:垃圾清理:与CMS不同的是,G1可以采用拷贝算法,直接将整个Region中的对象直接拷贝到另一个Region。而这个阶段,G1只选择垃圾较多的Region来清理,并不是完全清理。