回收算法
标记清除算法
根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,
则标记为垃圾,在清除。
优点:算法简单
缺点:容易产生内存碎片
标记整理算法
根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,
则标记为垃圾
标记整理与标记清除区别在于:避免标记清除算法产生的碎片问题,
清除垃圾过程中,会将可用的对象实现移动,内存空间更加具有连续性。
优点:没有内存的碎片问题
缺点:整理过程中会产生内存地址移动,效率可能偏低。
标记复制算法
根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,
将正在被引用的对象拷贝到to区中,让后再直接清理整个from区,在交换位置。
优点:不会产生内存碎片
缺点:比较占内存空间
分代算法
image.png
分代算法中主要分成三代: 新生代/from或者 to/老年代
默认 新生代(Young)与老年代(Old)的比例的值为 1:2 (该值可以通过参数–XX:NewRatio 来指定)。
默认的 Eden:from:to=8:1:1 (可以通过参数 –XX:SurvivorRatio 来设定)。
新生代:刚创建的对象都存放在新生代中eden区,当eden区空间内存满之后,则根据GC可达分析算法,将幸存的对象拷贝到to区中,并且寿命+1. 如果该对象的寿命>15的情况下
则将该对象放入到老年代中。
老年代:Minor GC新生代GC ,回收多次如果该对象还一直被引用的情况下,则放入到老年代中,如果新生代和老年代内存都满的情况下,则会触发FullGC
总结:
1.对象首先分配到eden区(伊田园区) 新生代GC (Minor GC)
2.新生代空间不足时,触发Minor GC,将eden区(伊田园区)存活的对象采用标记复制算法放入到to区中,并且该对象的寿命+1
注意:Minor GC因为标记复制算法,会触发stop the world 暂停其他用户的线程,等待垃圾回收结束之后,其他的用户线程才会继续执行。
3.如果该对象的寿命>15的情况下,则将该对象放入到老年代中,对象寿命放入在对象头中。
4.当老年代空间不足的时候,会触发FullGC 采用标记清理/整理算法
5.新生代GC非常频繁,速度比老年代GC要高。
GC相关参数
Stop-The-World
在垃圾回收过程中经常涉及到对对象的挪动(比如上文提到的对象在Survivor 0和Survivor 1之间的复制),进而导致需要对对象引用进行更新。为了保证引用更新的正确性,Java将暂停所有其他的线程,这种情况被称为“Stop-The-World”,导致系统全局停顿。Stop-The-World对系统性能存在影响,因此垃圾回收的一个原则是尽量减少“Stop-The-World”的时间。
回收算法:
误区:没有引用计数算法
1.标记清除算法
2.标记整理算法
3.标记复制算法
回收算法是针对不同的场景使用
按照分代使用
新生代:标记复制算法
老年代:标记清除/标记整理
为什么新生代使用 标记复制算法?而老年代使用标记清除/标记整理
?
为什么新生代使用 标记复制算法?而老年代使用标记清除/标记整理
?
因为新生代gc非常频繁,所以选择效率比较高的垃圾回收算法。、
标记清除算法:
优点:算法非常简单。
缺点:空间地址不连续
为什么标记清除算法:空间地址不连续 没有整理
标记整理算法:
优点:空间地址保持连续
缺点:速度慢、会产生移动内存地址 在移动过程中其他线程无法访问堆内存。
标记复制算法:
优点:空间地址保持连续、效率比标记整理算法要高。
缺点: 存在两个空间,占用空间。
分为两个区域:from 和to区 相等。
From和to切换
原理:
当我们堆内存触发gc的时候,在from区中将可用对象拷贝到to中,在直接将整个from
区清空,依次循环切换。
垃圾收集器 并行、串行、cms g1
分代算法:
首先,对我们堆内存空间实现分代,核心分为新生代、老年代
新生代:刚创建的对象一般的情况下都是放在新生代中
分为:eden区() from区 to区
刚创建的对象会放在eden区,当我们新生代eden区空间满的
情况下,会将引用的对象拷贝到to区中,如果gc回收15次的时候
发现该对象还一直被使用的情况下,该对象就会晋升为老年代中。
老生代:
存储空间比例:
1.默认的情况下新生代与老年代存储空间比例是1:2
2.新生代中eden区与from/to区
为什么新生代中from/to区 比例是1:1
因为新生代中使用的标记复制算法
老年代在什么的情况下会发生fullgc
1.在新生代和老年代有堆内存空间都快满的时候。
新生代GCMinorGC
老年代fullgc
当我们老年代gc开始回收垃圾的时候,也会触发新生代gc回收。
老年代在什么时候触发:
当我们老年代空间装不下的时候。
依次内推如何演示新生代gc
Java垃圾收集算法 cms、g1收集器
1.标记清除、标记整理、标记复制算法(引用计数法)
1.标记清除算法:
优点:算法实现简单
缺点: 内存空间不连续、空间利用率不高 容易产生碎片化
2.标记整理算法
优点:空间具有连续性 没有产生碎片化的问题 效率比较低
缺点:对象的应用内存地址有可能会发生变化
3.标记复制算法
优点:效率比较高,保证空间连续性的问题
缺点:以空间的方式换时间
分代算法:
分为新生代和老年代
新生代:刚创建的对象都存放到新生代中 ,在新生代中有分成三个区域。
新生代中分为 eden区、from和to区
刚创建的对象存放到eden区,当eden区如果满的时候,幸存的对象晋升为存放到
From或者是to区
新生代触发的GCMinorGC
老年代触发的GCFullGC
那些对象会晋升到老年代中?
1.年限达到当gc多次在回收的时候,如果能够一直引用到一个阈值的情况下。直接晋升到老年代中。
2.直接是大对象
在默认的情况下 新生代与老年代存储空间比例 是为1:2
在默认的情况下,新生代中 eden区域与from或者是to占比是为8:1:1
程序发生内存溢出:存放的对象空间大小大于我们老年代的空间大小。
因为在整合堆内存中,新生代触发gc回收次数一定比老年代多。
为什么在分代算法中 新生代中有from和to区大小一样。
因为新生代中gc触发非常频繁,为了能够更加高效清理垃圾,所以采用标记复制算法。
垃圾收集器在什么开始触发收集垃圾?
当新生代或者是老年代内存满的情况下,开始触发垃圾
垃圾收集器之前频繁推出垃圾收集器
Stop-The-World 问题
Stop-The-World:当我们垃圾收集器在回收垃圾的时候,
当垃圾回收线程在清理垃圾的时候,会暂停我们的所以用户线程。
导致当前的用户线程短暂卡
在生产环境中调优jvm: 不要频繁触发垃圾回收或者是降低用户线程阻塞的时间
所有的收集器:在回收垃圾的时候都会暂停我们用户的线程
怎样避免触发垃圾收集器频繁回收?
1.堆内存空间设置比较大
2.堆内存初始化 与最大值一定保持一致。
3.生产环境中不要去调用System.gc();
垃圾收集器 与垃圾收集算法区别:
垃圾收集器:串行、并行收集、CMS、G1 Java11 ZGC收集器,能够降低对我们用户线程暂停的时间或者用户线程和GC线程同时运行
垃圾收集算法:回收算法:标记清除、标记整理、标记复制、分代算法
Stop-The-World
当我们在触发gc回收的时候,有可能会暂停用户的线程。
JVM参数
如果存放的对象空间大于新生代空间,该对象会直接放到老年代中。
GC核心参数
-Xms100 -Xmx
1、-Xms
初始大小内存,默认为物理内存 1/64,等价于 -XX:InitialHeapSize
2、-Xmx
最大分配内存,默认为物理内存的 1/4,等价于 -XX:MaxHeapSize
3、-Xss
设置单个线程栈的大小,一般默认为 512-1024k,等价于 -XX:ThreadStackSize
4、-Xmn
设置年轻代的大小
整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小
持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
5、-XX:MetaspaceSize
设置元空间大小
元空间的本质和永久代类似,都是对 JVM 规范中的方法区的实现。
元空间与永久代之间最大区别:元空间并不在虚拟机中,而是使用本地内存
因此默认情况下,元空间的大小仅受本地内存限制,元空间默认比较小,我们可以调大一点
6、-XX:+PrintGCDetails
输出详细GC收集日志信息
7、-XX:SurvivorRatio
设置新生代中 eden 和 S0/S1 空间比例,默认 -XX:SurvivorRatio=8,Eden : S0 : S1 = 8 : 1 :
8、-XX:NewRatio
配置年轻代和老年代在堆结构的占比,默认 -XX:NewRatio=2 新生代占1,老年代占2,年轻代占整个堆的 1/3
9、-XX:MaxTenuringThreshold
设置垃圾最大年龄
新生代与老年代参数比例设置
-XX:+PrintGCDetails -verbose:gc -XX:SurvivorRatio=2 -XX:NewRatio=1
GC日志参数分析
package com.taotao.jvm1.day08;
/**
*@author tom
*Date 2020/8/25 0025 10:07
*gc日志回收
* -XX:+PrintGCDetails -verbose:gc -XX:SurvivorRatio=2 -XX:NewRatio=1
*/
public class Test02 {
public static void main(String[] args) {
// -Xms20m -Xmx20m -XX:+PrintGCDetails -verbose:gc
//-Xms20m -Xmx20m -XX:+PrintGCDetails -verbose:gc
System.out.println("my");
}
}
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" -XX:+PrintGCDetails -verbose:gc "-javaagent:D:\program\idea\IntelliJ IDEA 2020.1\lib\idea_rt.jar=54958:D:\program\idea\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;F:\works\2020\mayiketang\7\jvm\jvm1\target\classes;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.3.2.RELEASE\spring-boot-starter-web-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter\2.3.2.RELEASE\spring-boot-starter-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\2.3.2.RELEASE\spring-boot-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.2.RELEASE\spring-boot-autoconfigure-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.3.2.RELEASE\spring-boot-starter-logging-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;C:\Users\Administrator\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\Administrator\.m2\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.3.2.RELEASE\spring-boot-starter-json-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.11.1\jackson-databind-2.11.1.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.1\jackson-annotations-2.11.1.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.11.1\jackson-core-2.11.1.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.1\jackson-datatype-jdk8-2.11.1.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.1\jackson-datatype-jsr310-2.11.1.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.1\jackson-module-parameter-names-2.11.1.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.2.RELEASE\spring-boot-starter-tomcat-2.3.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.37\tomcat-embed-core-9.0.37.jar;C:\Users\Administrator\.m2\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.37\tomcat-embed-websocket-9.0.37.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-web\5.2.8.RELEASE\spring-web-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-beans\5.2.8.RELEASE\spring-beans-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-webmvc\5.2.8.RELEASE\spring-webmvc-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-aop\5.2.8.RELEASE\spring-aop-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-context\5.2.8.RELEASE\spring-context-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-expression\5.2.8.RELEASE\spring-expression-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-core\5.2.8.RELEASE\spring-core-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-jcl\5.2.8.RELEASE\spring-jcl-5.2.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar;C:\Users\Administrator\.m2\repository\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar" com.taotao.jvm1.day08.Test02
my
Heap
PSYoungGen total 75264K, used 6451K [0x000000076c800000, 0x0000000771c00000, 0x00000007c0000000)
eden space 64512K, 10% used [0x000000076c800000,0x000000076ce4ceb8,0x0000000770700000)
from space 10752K, 0% used [0x0000000771180000,0x0000000771180000,0x0000000771c00000)
to space 10752K, 0% used [0x0000000770700000,0x0000000770700000,0x0000000771180000)
ParOldGen total 172032K, used 0K [0x00000006c5800000, 0x00000006d0000000, 0x000000076c800000)
object space 172032K, 0% used [0x00000006c5800000,0x00000006c5800000,0x00000006d0000000)
Metaspace used 3441K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 385K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0
image.png
image.png
/**
* @ClassName Test001
* @Author 蚂蚁课堂余胜军 QQ644064779 www.mayikt.com
* @Version V1.0
**/
public class Test001 {
// -Xms20m -Xmx20m -XX:+PrintGCDetails -verbose:gc
//-Xms20m -Xmx20m -XX:+PrintGCDetails -verbose:gc
public static void main(String[] args) {
ArrayList mayiktList = new ArrayList<>();
// mayiktList.add(new byte[12 * 1024 * 1024]);
mayiktList.add(new byte[15 * 1024 * 1024]);
}
}
[GC (Allocation Failure) [PSYoungGen: 1626K->488K(6144K)] 1626K->688K(19968K), 0.0039387 secs] [Times: user=0.14 sys=0.00, real=0.00 secs]
新生代发生GC ,从堆内存回收前占用:1626k 回收后变为占用488K ,后面表示GC的用时。
[Full GC (Allocation Failure) [PSYoungGen: 488K->0K(6144K)] [ParOldGen: 296K->593K(13824K)] 784K->593K(19968K), [Metaspace: 3099K->3099K(1056768K)], 0.0043821 secs]
当发生老年代GC时,也会触发新生代GC,新生代堆回收前占用488K,回收后占用0K
,ParOldGen 老年代回收前占用784K,回收后占用593K
GC分析大对象
当我们直接存一个大的对象的时候,比新生代占用空间还有大时,会直接晋升为老年代。