JVM五个区:
程序计数器:像CPU的pc一样,保存当前指令执行的地址
java栈:每个线程执行的方法可能不同,因此每个线程都有属于自己的栈,互不影响
本地方法栈:本地方法栈为执行本地方法服务的
堆:堆内存主要来存储对象本身
方法区:被线程共享的区域,放静态变量/常量/编译器编译后的代码
GC问题
什么时候进行垃圾回收?
当实例化对象的时候,先去看伊甸园满没满,
没满,对象直接在伊甸园存储
满了,会进行一次Minor GC,
然后再看看伊甸园有没有满,
满了继续看存活区和老年代,能放就放到那里,
它们也都满了的话,会对老年代进行一次full垃圾回收,
再不足会OutofMemoryError。
垃圾回收算法有哪些?
1.标记清除
标记阶段,程序会检查每个对象是否为存活对象,如果是存活对象,会打上标记
清除阶段,会收回标记收回对象, 若空闲分区连续那就会融合
不足:
标记和清除过程效率都不高;
会产生大量不连续的内存碎片,导致无法给大对象分配内存。
2.标记整理。
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
优点:
不会产生内存碎片
不足:
需要移动大量对象,处理效率比较低
3.复制
将内存分为两块,每次只使用其中一块,当这一块用完就把还存活的放到另外一块,对使用过的在进行一次清理,现在商业虚拟机都采用这种算法回收新生代。
4.分代收集
分为新生代和老生代
新生代使用:复制算法
老生代:标记清楚,标记整理算法
垃圾收集器
CMS和G1
CMS过程
初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿。
并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿。
重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿。
并发清除:不需要停顿。
缺点:
吞吐量低:低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高。
无法处理浮动垃圾,可能出现 Concurrent Mode Failure。浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。
标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC。
G1回收
G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。
过程:
初始标记
并发标记
最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。
筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。