欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java的垃圾回收机制详细介绍

程序员文章站 2022-03-28 13:11:12
垃圾回收算法思想引用计数复制拷贝标记清除标记整理主要的垃圾收集器Serial 串行只使用一个线程进行垃圾的回收。会暂停所有的用户线程。不适合服务器环境,类似于餐厅需要打扫垃圾,需要请客人出去,然后开始打扫垃圾。UserSerialGCParallel 并行多个垃圾收集线程并行的回收垃圾,用户线程是暂停的。适合允许中途暂停,适合弱交互的场景。性能比串行好。UserParall......

垃圾回收算法思想

  • 引用计数
  • 复制拷贝:将内存区域分为两块,一块存储对象,如果对象满了,那么将存活的对象移动到另外的一块区域中。(新生代中)
  • 标记清除:先标记、然后再整理。会存在效率低下的问题,存在内存碎片。
  • 标记整理:将存活的对象移动到另外一块区域,然后清除非存活的对象区域。(老年代中)
-XX:+UseSerialGC 

只使用一个线程进行垃圾的回收。会暂停所有的用户线程。不适合服务器环境,类似于餐厅需要打扫垃圾,需要请客人出去,然后开始打扫垃圾。主要的收集器:Serial(Young) SerialOld(Old)
查看是否生效
Java的垃圾回收机制详细介绍
开启后会使用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: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 标记算法无法整理空间碎片,不得不通过担保机制对堆内存进行压缩。

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

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

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

  • StopTheWorld\color{#FF0000}{Stop The World更加可控,用户可以设置停顿时间。}

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

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

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) 

UserParallelGC\color{#FF0000}{默认的垃圾回收是并行UserParallelGC}
开始串行垃圾回收

-XX:+UseSerialGC 
  • 垃圾回收器选择
    单核CPU或小内存
-XX:+UseSerialGC 

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

-XX:+UseParallelGC 

对响应时间有要求的

-XX:+UseConcMarkSweepGC 

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

本文地址:https://blog.csdn.net/BtWangZhi/article/details/104202156

相关标签: JVM

上一篇: 说出来吓着你

下一篇: 减肥ing