
文章插图
我们首先对大概念进行介绍:
- 新生代:用于存放新产生的内存数据,清除频繁
- 老生代:用于存放一直使用的内存数据,只有当内存占满时才会清理
- 伊甸园:用于存放所有的新产生的内存数据
- 幸存区From:用于存放未被垃圾回收的数据
- 幸存区To:用于进行未被垃圾回收的数据的复制方法
- 幸存值:用于表示内存数据的常用程度,所有内存数据进入时默认值为0,
- 首先我们的新数据都会进入到新生代的伊甸园中去,默认幸存值为0
- 当伊甸园数据满后,会进行gc,这时我们进行标记清除法,将不需要的内存筛出
- 同时将幸存下来的内存数据放入到幸存区From,幸存值+1,同时进行From和To区间的对调
- 我们继续进行储存直到伊甸园再次占满,对整个新生代进行gc
- 首先将幸存区From的幸存内存放入To中并将伊甸园的幸存数据放入To,进行区间调换,幸存值+1
- 直到幸存值达到一个阈值(默认为6或者15),该内存数据就会被移动到老年代,新生代仍旧继续工作
- 直至新生代和老年代全部都占满后,这时我们就需要进行大型的垃圾回收,也就是我们之前提到的Full gc!
含义参数堆初始大小-Xms堆最大大小-Xmx 或 -XX:MaxHeapSize=size新生代大小-Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )幸存区比例(动态)-XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy幸存区比例-XX:SurvivorRatio=ratio晋升阈值-XX:MaxTenuringThreshold=threshold晋升详情-XX:+PrintTenuringDistributionGC详情-XX:+PrintGCDetails -verbose:gcFullGC 前 MinorGC (小gc)-XX:+ScavengeBeforeFullGC分代垃圾回收案例展示我们通过一个简单的实例来展示分代垃圾回收的实际演示:
// 相关配置信息:配置默认大小,设置回收方法,显示GC详情,开启FullGC前进行gc// -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC/*首先我们展示不添加内存的状况*/package cn.itcast.jvm.t2;import java.util.ArrayList;public class Demo2_1 {private static final int _512KB = 512 * 1024;private static final int _1MB = 1024 * 1024;private static final int _6MB = 6 * 1024 * 1024;private static final int _7MB = 7 * 1024 * 1024;private static final int _8MB = 8 * 1024 * 1024;public static void main(String[] args) throws InterruptedException {new Thread(() -> {ArrayList<byte[]> list = new ArrayList<>();}).start();System.out.println("sleep....");Thread.sleep(1000L);}}/*其中def new generation,eden space是新生代,tenured generation是老年代,from,to幸存区Heap def new generationtotal 9216K, used 4510K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)eden space 8192K,55% used [0x00000000fec00000, 0x00000000ff067aa0, 0x00000000ff400000)from space 1024K,0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)tospace 1024K,0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000) tenured generationtotal 10240K, used 0K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)the space 10240K,0% used [0x00000000ff600000, 0x00000000ff600000, 0x00000000ff600200, 0x0000000100000000) Metaspaceused 4362K, capacity 4714K, committed 4992K, reserved 1056768Kclass spaceused 480K, capacity 533K, committed 640K, reserved 1048576K*//*然后我们展示添加1mb的情况*/package cn.itcast.jvm.t2;import java.util.ArrayList;public class Demo2_1 {private static final int _512KB = 512 * 1024;private static final int _1MB = 1024 * 1024;private static final int _6MB = 6 * 1024 * 1024;private static final int _7MB = 7 * 1024 * 1024;private static final int _8MB = 8 * 1024 * 1024;public static void main(String[] args) throws InterruptedException {new Thread(() -> {ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_1MB]);}).start();System.out.println("sleep....");Thread.sleep(1000L);}}/*我们可以发现新生代数据增加,老年代未发生变化Heap def new generationtotal 9216K, used 5534K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)eden space 8192K,67% used [0x00000000fec00000, 0x00000000ff167a40, 0x00000000ff400000)from space 1024K,0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)tospace 1024K,0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000) tenured generationtotal 10240K, used 0K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)the space 10240K,0% used [0x00000000ff600000, 0x00000000ff600000, 0x00000000ff600200, 0x0000000100000000) Metaspaceused 4354K, capacity 4714K, committed 4992K, reserved 1056768Kclass spaceused 480K, capacity 533K, committed 640K, reserved 1048576*//*最后需要补充讲解一点:当我们的新生代不足以装载数据内存时,我们会直接将其装入老年代(老年代能够装载情况下)*/package cn.itcast.jvm.t2;import java.util.ArrayList;public class Demo2_1 {private static final int _512KB = 512 * 1024;private static final int _1MB = 1024 * 1024;private static final int _6MB = 6 * 1024 * 1024;private static final int _7MB = 7 * 1024 * 1024;private static final int _8MB = 8 * 1024 * 1024;public static void main(String[] args) throws InterruptedException {new Thread(() -> {ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_8MB]);}).start();System.out.println("sleep....");Thread.sleep(1000L);}}/*我们会发现eden的值未发生变化,但是tenured generation里面装载了8192KHeap def new generationtotal 9216K, used 4510K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)eden space 8192K,55% used [0x00000000fec00000, 0x00000000ff067a30, 0x00000000ff400000)from space 1024K,0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)tospace 1024K,0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000) tenured generationtotal 10240K, used 8192K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)the space 10240K,80% used [0x00000000ff600000, 0x00000000ffe00010, 0x00000000ffe00200, 0x0000000100000000) Metaspaceused 4360K, capacity 4714K, committed 4992K, reserved 1056768Kclass spaceused 480K, capacity 533K, committed 640K, reserved 1048576K*//*当然,当我们的新生代和老年代都不足以装载时,系统报错~*/package cn.itcast.jvm.t2;import java.util.ArrayList;public class Demo2_1 {private static final int _512KB = 512 * 1024;private static final int _1MB = 1024 * 1024;private static final int _6MB = 6 * 1024 * 1024;private static final int _7MB = 7 * 1024 * 1024;private static final int _8MB = 8 * 1024 * 1024;public static void main(String[] args) throws InterruptedException {new Thread(() -> {ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_8MB]);list.add(new byte[_8MB]);}).start();System.out.println("sleep....");Thread.sleep(1000L);}}/*我们首先会看到他在Full gc之前做了一次小gc,然后做了一次Full gc,可是这并无法解决问题[GC (Allocation Failure) [DefNew: 4345K->999K(9216K), 0.0016573 secs][Tenured: 8192K->9189K(10240K), 0.0022899 secs] 12537K->9189K(19456K), [Metaspace: 4352K->4352K(1056768K)], 0.0039931 secs] [Times: user=0.00 sys=0.00, real=0.00 secs][Full GC (Allocation Failure) [Tenured: 9189K->9124K(10240K), 0.0018331 secs] 9189K->9124K(19456K), [Metaspace: 4352K->4352K(1056768K)], 0.0018528 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 然后系统进行报错Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space at cn.itcast.jvm.t2.Demo2_1.lambda$main$0(Demo2_1.java:20) at cn.itcast.jvm.t2.Demo2_1$$Lambda$1/1023892928.run(Unknown Source) at java.lang.Thread.run(Thread.java:750)最后我们可以看到老年代占用了89%,第一个数据仍旧保存,但第二个数据无法保存导致报错Heap def new generationtotal 9216K, used 366K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)eden space 8192K,4% used [0x00000000fec00000, 0x00000000fec5baa8, 0x00000000ff400000)from space 1024K,0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)tospace 1024K,0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000) tenured generationtotal 10240K, used 9124K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)the space 10240K,89% used [0x00000000ff600000, 0x00000000ffee93c0, 0x00000000ffee9400, 0x0000000100000000) Metaspaceused 4379K, capacity 4704K, committed 4992K, reserved 1056768Kclass spaceused 480K, capacity 528K, committed 640K, reserved 1048576K我们还需要注意的是:即使内存不足发生报错,但该程序不会结束;系统只会释放自己当前项目的进程而不会影响其他进程*/
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 黑莓q5用安装微信的方法a 用黑莓自带的印象笔记手敲的 看不懂的宝宝们在私聊我吧
- 未来两个月小宇宙爆发逆袭黑马 学习运超好的4大星座
- JVM学习笔记——内存结构篇
- 【lwip】08-ARP协议一图笔记及源码实现
- 用一台笔记本电脑如何赚钱(笔记本电脑赚钱的办法)
- 小米笔记本Pro15增强版评测_小米笔记本Pro15增强版评测表现
- 笔记本电脑CF中烟雾头怎么调(win10cf新版本烟雾保护头怎么调)
- 笔记本电脑配置高低怎么区分(笔记本电脑看什么配置判断好坏)
- 四 【单片机入门】应用层软件开发的单片机学习之路-----ESP32开发板PWM控制电机以及中断的使用
- pytorch、paddlepaddle等环境搭建 深度学习环境搭建常用网址、conda/pip命令行整理
