JVM垃圾回收算法
关于GC后面会持续更新,这次先简单的整体总结一下GC,才疏学浅,希望大家多多指教,共同和学习共同进步!
一、如何定位垃圾
1:引用计数法:对被引用的对象进行标记 +1,当标记为0时,就是需要回收的垃圾对象,但是这种方法只能标记出部分对象。但是对于循环引用的对象就无法标记了
如下图这种对象就不能被回收:
2:跟可达算法
就是解决上述1中的循环引用不能垃圾回收的算法。
当一个程序main方法运行起来之后,运行的当前线程的线程栈中的局部变量,以及从class文件中的静态变量,还有一些常量池和JNI指针引用的到的那些变量。从跟对象可达的都不是垃圾对象,不可达的都是垃圾对象。如图灰色的部分就会被回收,因为是不可达对象。
二、常见的垃圾回收算法
1:标记清除算法:找到垃圾直接清除,但是内存位置不连续,容易产生内存碎片。
2:复制算法:将内存分为两块,将一块中的非垃圾对象拷贝到另一个区域,然后将该区域全部清除。 这样会比较浪费空间。
3:标记压缩算法:先对垃圾对象标记,然后整理,压缩,之后清除,没有内存碎片,但是效率低下,主要是慢在整理和压缩这块。
三、JVM的内存分代模型(用于垃圾分代回收算法)
1:部分垃圾回收器使用的模型:
为什么是部分:因为在有些垃圾回收器中已经不区分新生代,老年代的。因为在部分垃圾回收器中会将堆内存分为老年代,新生代,为了提高效率针对不同的分代,使用不同的垃圾回收器。
2:新生代 + 老年代 + 永久代(JDK1.7版本)/ 元数据区(JDK1.8)
A:永久代 、元数据区都是放 class的
B:永久代必须指定大小限制,元数据可以设置,也可以不设置,无上限(受限于物理内存)
C:字符串常量:1.7-永久代,1.8在 堆中
D:方法区:是逻辑概念。1.7 永久代,1.8元数据区
3:新生代 = Eden + 2个suvivor区(suvivor0,suvivor1):
A:年轻代进行垃圾回收之后,大多数的垃圾对象都会被回收,80%-90%,没有被回收的垃圾进入到suvivor0
B:年轻代再次YGC,没有被回收的垃圾对象:eden + suvivor0 全部进入到suvivor1
C:年轻代再次YGC,没有被回收的垃圾对象:eden + suvivor1 全部进入到suvivor0
D:当垃圾对象到达一定的年龄之后就会将垃圾对象这些顽固分子放入到老年代
E:还有就是suvivor区域装不下就会直接放到老年代
4:老年代
A:老年代放的都是YGC无法回收的顽固分子垃圾对象,老年代采用Full GC的方式,
B:full gc会产生STW:stop the world :停止所有的线程、等gc结束之后才开始执行
C:MinorGC = YGC; MajorGC = FGC
四、常见的垃圾回收器
如上图10种:紫色的不在分老年代和新生代了。
Serial 年轻代 串行回收
PS 年轻代 并行回收
ParNew 年轻代 配合CMS的并行回收
SerialOld 老轻代 串行回收
ParallelOld 老轻代 并行回收
ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms),比较复杂
Eplison:jdk自己内部测试的一个gc,是一个空的gc,什么事也没有干
目前关于JVM的调优主要涉及到下图红色框中的部分,以后可能会涉及大紫色的
1.8默认的垃圾回收:PS + ParallelOld
JVM参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
-XX:+PrintCommandLineFlags 命令行参数
JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-XX:+PrintFlagsFinal 最终参数值
-XX:+PrintFlagsInitial 默认参数值