Java GC调优 基础
Garbage(垃圾)
1.定义:
1、如果对象没有任何引用,则该对象为垃圾。
2、循环引用的对象,没有外来引用。
2.如何寻找垃圾?
1.reference count 引用计数
2.Root Searching 根可达算法
啥叫root?
GC roots包括线程栈变量 静态变量 常量池 JNI指针等
凡是不能被根引用到的 都算是 garbage。
3.常见的垃圾回收算法
-
Mark-Sweep(标记清除)
找到垃圾,然后标记,然后清除。位置不连续,容易产生碎片
-
Copying(拷贝)
把内存区域分成两部分,分别使用。效率高,但浪费空间。
-
Mark-Compact(标记压缩)
没有碎片,效率比copy略低。
4.JVM分代算法
-
新生代+ 老年代 + 元数据区(1.8)
- 元数据存储class
- 元数据可设置也可不设置。(上限受限于物理内存)
- 元数据存储class
-
内存逻辑分区
啥叫新生代啥又叫老年代呢?
比如奥特赛文就是老年代,他儿子赛罗奥特曼就是新生代了——
不皮了,我们看看这个:
新生代是指左边的eden和两个survivor区,而老年代就是右边的old。一般新生代和老年代的大小比例是1:3。
MinorGC = Minor Garbage collect 新生代进行的垃圾回收
MajorGC = Major Garbage Collect 老年代进行的垃圾回收
当一个对象被创建出来之后,它就会进入新生代的eden。一段时间后,Eden就会把除了垃圾之外的对象复制到survivor(我们称之为s0)中,然后再把Eden清空。再又一段时间后,又进行一次Minor GC,又把Eden中除了垃圾之外的对象复制到另一个survivor(这叫s1),再把Eden清空。再之后,重复上述步骤。
像这样如此往复,当对象的年龄足够大之后,就会发往老年代(tuenured)
Eden和survivor的大小比是8:1:1。新生代的垃圾回收算法使用的是Copying,效率相对较高,而且其内部内存的分配又能有效地节约空间。
可能有人已经注意到了,如果eden放不下那个新的对象咋办?如果这样,那个对象将被直接发往老年代。
为了更好地适应不同程序内存状况,虚拟机并不硬性要求对象年龄达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入年老代。
老年代:
1.一直在重复的复制的
2.老年代充满了FGC
FGC 即FULL GC,也成MajorGC会使用Mark Compact算法,其效率较低。赢尽量减少FGC的次数。
5.常见的垃圾回收器
新生代
Serial
程序运行一段时间,当Eden内存满了之后,程序就会停止(stop-the-world),进行一次垃圾回收,然后程序继续运行。周而复始。用于年轻代,单线程,串行回收。
STW - STW阶段,应用程序线程被暂停,以便gc执行其工作。
Parallel Scavenge
同Serial,但其进行的是串行回收。
ParNew
用户配合CMS回收
老年代
SerialOld 同新生代
ParallelOld 同新生代
CMS 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)
更新的GC:
- G1(10ms)
- ZGC (1ms) PK C++
- Shenandoah
- Eplison
ZGC具体可查阅https://wiki.openjdk.java.net/display/zgc/Main
1.8默认的垃圾回收:PS + ParallelOld