Java--垃圾回收机制

垃圾回收算法思想

  • 引用计数
  • 标记清除:先标记、然后再整理。会存在效率低下的问题,存在内存碎片,进而提前触发GC。
  • 复制拷贝:将内存区域分为两块,一块存储对象,如果对象满了,那么将存活的对象移动到另外的一块区域中。(新生代中)空间利用率底。
  • 标记整理:将存活的对象移动到一边,然后清除非存活的对象区域。(老年代中),相比复制算法,多了移动。

在这里插入图片描述
如何标记一个对象是垃圾
引用计数法
可达性分析:由根节点(类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量)依次变量,如果不可达,那么判定为垃圾。

如下所说的并行和并发和Java并发编程不同
并行:指多个垃圾回收器并行的工作,但此时用户线程仍然处于等待状态,适合后台处理等弱交互的场景。
并发:指用户线程和垃圾回收器同时执行,可能是交替执行,执行垃圾回收的时候不会停顿程序的运行,适合对响应时间有要求的场景。

-XX:+UseSerialGC

只使用一个线程进行垃圾的回收。会暂停所有的用户线程。不适合服务器环境,类似于餐厅需要打扫垃圾,需要请客人出去,然后开始打扫垃圾。主要的收集器:Serial(Young) SerialOld(Old)
查看是否生效
在这里插入图片描述
开启后会使用Serial(Young区间,一个线程)+Serial Old(Old区用,一个线程)的收集器组合
表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法、老年代使用标记-整理算法。
测试

    public static void main(String[] args) throws InterruptedException {
    	String str="123";
    	while(true) {
    		str+=str+new Random().nextInt(7777)+new Random().nextInt(8888);
    		str.intern();
    	}
	}

添加JVM参数

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC

打印结果

-XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC 
[GC (Allocation Failure) [$\color{#FF0000}{DefNew}$: 2677K->320K(3072K), 0.0051447 secs] 2677K->1266K(9920K), 0.0537604 secs] [Times: user=0.00 sys=0.00, real=0.05 secs] 
[GC (Allocation Failure) [DefNew: 2836K->0K(3072K), 0.0050224 secs] 3782K->2673K(9920K), 0.0051220 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 1461K->0K(3072K), 0.0034208 secs] 4134K->4080K(9920K), 0.0035157 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 1407K->0K(3072K), 0.0021344 secs] 5487K->5487K(9920K), 0.0022028 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 1460K->1460K(3072K), 0.0000475 secs][Tenured: 5487K->3375K(6848K), 0.0076576 secs] 6948K->3375K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0083059 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [$\color{#FF0000}{DefNew}$: 53K->0K(3072K), 0.0006282 secs][$\color{#FF0000}{Tenured}$: 6189K->4782K(6848K), 0.0062502 secs] 6242K->4782K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0070148 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [Tenured: 4782K->4765K(6848K), 0.0074241 secs] 4782K->4765K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0075259 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.lang.StringBuilder.toString(Unknown Source)
	at com.test01.TextMain.main(TextMain.java:149)
Heap
 def new generation   total 3072K, used 108K [0x00000000ff600000, 0x00000000ff950000, 0x00000000ff950000)
  eden space 2752K,   3% used [0x00000000ff600000, 0x00000000ff61b3c8, 0x00000000ff8b0000)
  from space 320K,   0% used [0x00000000ff900000, 0x00000000ff900000, 0x00000000ff950000)
  to   space 320K,   0% used [0x00000000ff8b0000, 0x00000000ff8b0000, 0x00000000ff900000)
 tenured generation   total 6848K, used 4765K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
   the space 6848K,  69% used [0x00000000ff950000, 0x00000000ffdf75c0, 0x00000000ffdf7600, 0x0000000100000000)
 Metaspace       used 2727K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 299K, capacity 386K, committed 512K, reserved 1048576K

=============================================================================================

-XX:+UseSerialOldGC

已经被优化掉了,在Java8中配置这个常数会执行失败。

=============================================================================================

-XX:+UseParNewGC

多个线程并行的垃圾回收器,用户线程是暂停的。适合允许中途暂停,适合弱交互的场景。性能比串行好。
主要的收集器:ParNew(Young) Serial Old(Old)新生代使用复制算法,老年代使用标记-整理算法。
新生代会存在多个收集线程并行收集、老年代会存在一个线程。 \color{#FF0000}{新生代会存在多个收集线程并行收集、老年代会存在一个线程。} 新生代会存在多个收集线程并行收集、老年代会存在一个线程。

-XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC 
[GC (Allocation Failure) [ParNew: 2676K->319K(3072K), 0.0011021 secs] 2676K->1285K(9920K), 0.0011538 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 2833K->49K(3072K), 0.0011102 secs] 3800K->2757K(9920K), 0.0011778 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1509K->24K(3072K), 0.0009669 secs] 4218K->4138K(9920K), 0.0009956 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1430K->6K(3072K), 0.0010982 secs] 5544K->5526K(9920K), 0.0011277 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1465K->1465K(3072K), 0.0000128 secs][Tenured: 5520K->3603K(6848K), 0.0030239 secs] 6986K->3603K(9920K), [Metaspace: 2696K->2696K(1056768K)], 0.0030834 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 53K->2K(3072K), 0.0003297 secs][Tenured: 6415K->5009K(6848K), 0.0023247 secs] 6469K->5009K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0027113 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 5009K->4762K(6848K), 0.0042073 secs] 5009K->4762K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0042415 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.lang.StringBuilder.toString(Unknown Source)
	at com.test01.TextMain.main(TextMain.java:149)
Heap
 par new generation   total 3072K, used 108K [0x00000000ff600000, 0x00000000ff950000, 0x00000000ff950000)
  eden space 2752K,   3% used [0x00000000ff600000, 0x00000000ff61b3c8, 0x00000000ff8b0000)
  from space 320K,   0% used [0x00000000ff900000, 0x00000000ff900000, 0x00000000ff950000)
  to   space 320K,   0% used [0x00000000ff8b0000, 0x00000000ff8b0000, 0x00000000ff900000)
 tenured generation   total 6848K, used 4762K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
   the space 6848K,  69% used [0x00000000ff950000, 0x00000000ffdf6968, 0x00000000ffdf6a00, 0x0000000100000000)
 Metaspace       used 2727K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 299K, capacity 386K, committed 512K, reserved 1048576K
Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release

=============================================================================================

-XX:+UseParallelGC

运行在Server端的默认模式,收集器采用Parallel Scavenge(可控制吞吐量)+Serial Old的收集器组合。
吞吐量 花在垃圾回收器的时间和花在应用上的时间占比

XX:GCTimeRatio=N
-XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
[GC (Allocation Failure) [PSYoungGen: 1946K->502K(2560K)] 1946K->945K(9728K), 0.0012214 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 2292K->480K(2560K)] 2735K->1972K(9728K), 0.0011636 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 1919K->408K(2560K)] 7610K->6098K(9728K), 0.0005786 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 408K->392K(2560K)] 6098K->6082K(9728K), 0.0004204 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 392K->0K(2560K)] [ParOldGen: 5690K->3360K(7168K)] 6082K->3360K(9728K), [Metaspace: 2697K->2697K(1056768K)], 0.0068425 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 40K->32K(2560K)] 6199K->6190K(9728K), 0.0003943 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 32K->0K(2560K)] [ParOldGen: 6158K->4759K(7168K)] 6190K->4759K(9728K), [Metaspace: 2698K->2698K(1056768K)], 0.0026643 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 4759K->4759K(8704K), 0.0002609 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 4759K->4742K(7168K)] 4759K->4742K(8704K), [Metaspace: 2698K->2698K(1056768K)], 0.0074698 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.lang.StringBuilder.toString(Unknown Source)
	at com.test01.TextMain.main(TextMain.java:149)
Heap
 PSYoungGen      total 1536K, used 41K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 1024K, 4% used [0x00000000ffd00000,0x00000000ffd0a498,0x00000000ffe00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 7168K, used 4742K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 66% used [0x00000000ff600000,0x00000000ffaa1aa8,0x00000000ffd00000)
 Metaspace       used 2728K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 299K, capacity 386K, committed 512K, reserved 1048576K

=============================================================================================

-XX:+UseParallelOldGC

新生代中会用ParalleScavageGC,老年代中会用ParallelOldGC。新生代和老年代均为并行收集。

=============================================================================================

-XX:+UseConcMarkSweepGC
  • CMS(Concurrent Mark Sweep) 并发 用户线程和垃圾收集线程同时执行(有可能是并行,也有可能是并发),用户线程停顿的时间非常短,适合对响应时间有要求的场景。适合堆内存大、CPU核心多的服务器。
    开启参数后将会使用ParNew(新生代)+CMS(老年代)+Serial Old的收集器组合,Serial Old将会在CMS出错的后备收集器。
-XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=3497984 -XX:MaxTenuringThreshold=6 -XX:NewSize=3497984 -XX:OldPLABSize=16 -XX:OldSize=6987776 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC 
[GC (Allocation Failure) [ParNew: 2654K->319K(3072K), 0.0019591 secs] 2654K->1271K(9920K), 0.0020275 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 2802K->41K(3072K), 0.0014382 secs] 3754K->2698K(9920K), 0.0014976 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1483K->20K(3072K), 0.0010418 secs] 4141K->4065K(9920K), 0.0010867 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Initial Mark) [1 CMS-initial-mark: 4045K(6848K)] 5453K(9920K), 0.0002463 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Final Remark) [YG occupancy: 1408 K (3072 K)][Rescan (parallel) , 0.0001095 secs][weak refs processing, 0.0000158 secs][class unloading, 0.0002540 secs][scrub symbol table, 0.0004311 secs][scrub string table, 0.0001428 secs][1 CMS-remark: 4045K(6848K)] 5453K(9920K), 0.0010734 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-sweep-start]
[GC (Allocation Failure) [ParNew: 1408K->5K(3072K), 0.0012094 secs] 5453K->5438K(9920K), 0.0012342 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-sweep: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew (promotion failed): 1446K->1445K(3072K), 0.0003263 secs][CMS: 4043K->3340K(6848K), 0.0035269 secs] 5490K->3340K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0039165 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Initial Mark) [1 CMS-initial-mark: 6116K(6848K)] 6116K(9920K), 0.0001493 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
[GC (Allocation Failure) [ParNew: 53K->2K(3072K), 0.0003118 secs][CMS[CMS-concurrent-mark: 0.001/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 (concurrent mode failure): 6116K->4728K(6848K), 0.0036244 secs] 6169K->4728K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0040276 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [CMS: 4728K->4712K(6848K), 0.0032040 secs] 4728K->4712K(9920K), [Metaspace: 2697K->2697K(1056768K)], 0.0032459 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.lang.StringBuilder.toString(Unknown Source)
	at com.test01.TextMain.main(TextMain.java:149)
Heap
 par new generation   total 3072K, used 108K [0x00000000ff600000, 0x00000000ff950000, 0x00000000ff950000)
  eden space 2752K,   3% used [0x00000000ff600000, 0x00000000ff61b3b8, 0x00000000ff8b0000)
  from space 320K,   0% used [0x00000000ff8b0000, 0x00000000ff8b0000, 0x00000000ff900000)
  to   space 320K,   0% used [0x00000000ff900000, 0x00000000ff900000, 0x00000000ff950000)
 concurrent mark-sweep generation total 6848K, used 4712K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 2727K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 299K, capacity 386K, committed 512K, reserved 1048576K

经历的过程: 初始标记(用户线程会暂停) − 》并发标记(与用户线程并发) − 》 \color{#FF0000}{初始标记(用户线程会暂停)-》并发标记(与用户线程并发)-》} 初始标记(用户线程会暂停)》并发标记(与用户线程并发)
最终标记(在并发标记期间的记录需要最终确认,所以需要用户线程会暂停) − 》最终并发清除(与用户线程并发) \color{#FF0000}{最终标记(在并发标记期间的记录需要最终确认,所以需要用户线程会暂停)-》最终并发清除(与用户线程并发)} 最终标记(在并发标记期间的记录需要最终确认,所以需要用户线程会暂停)》最终并发清除(与用户线程并发)
优缺点
1 停顿时间短
2 垃圾回收线程与用户线程并发的执行时,会增大对堆内存的占用,如果回收线程不能在堆内存用尽之前执行垃圾回收,将会触发担保机制,及启动SerialGC,一个线程串行的进行回收,同时用户线程将会陷入等待,即Stop The World。
3 标记算法无法整理空间碎片,不得不通过担保机制对堆内存进行压缩。
4 对CPU敏感,

-XX:ParallelGCThreads=n SWT线程数
-XX:ConcGCThreads 并发的GC线程数

G1
将堆内存分割成不同的区域然后并发的对其进行垃圾回收。(Java8开始)

-XX:+UseG1GC

垃圾回收器:UseG1GC(Old)

  • CMS一样能与应用程序并发执行。

  • 不会产生很多内存碎片。

  • S t o p T h e W o r l d 更加可控,用户可以设置停顿时间。 \color{#FF0000}{Stop The World更加可控,用户可以设置停顿时间。} StopTheWorld更加可控,用户可以设置停顿时间。

  • 整体划分为各个不连续的内存区域,不存中绝对的新生代和老年代划分

  • 适合50%以上的堆被存活对象占用

  • 适合对象分配和晋升的速度变化非常大

  • 适合垃圾回收时间特别长,超过1秒。

  • 查看默认值的垃圾收集器

java -XX:+PrintCommandLineFlags -version

输出

D:\ProgramFiles\Java\jdk1.8.0_181>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=65279680 -XX:MaxHeapSize=1044474880 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

默认的垃圾回收是并行 U s e r P a r a l l e l G C \color{#FF0000}{默认的垃圾回收是并行UserParallelGC} 默认的垃圾回收是并行UserParallelGC
开始串行垃圾回收

-XX:+UseSerialGC
  • 垃圾回收器选择
    优先调整堆的大小,让服务器自己来选择。
    单核CPU或小内存
-XX:+UseSerialGC

多CPU,最大计算能力的采用

-XX:+UseParallelGC

对响应时间有要求的

-XX:+UseConcMarkSweepGC

收集器算法:新生代中的回收器均为复制算法,老年代中CMS采用的是标清算法,老年代中其他均为标整算法。

在这里插入图片描述

如何选择垃圾回收器

  • 优先调整堆的大小让服务器自己来选择。
  • 如果内存小于100M,使用串行收集器
  • 如果是单核,并且没有停顿时间的要求,串行或者JVM自己选。
  • 如果允许停顿时间超过1秒,选择并行或者JVM自己选。
  • 如果响应时间最重要,并且不能超过1秒,使用并发收集器。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值