47 jvm性能优化之GC日志参数分析

回收算法
标记清除算法
根据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<Object> 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分析大对象

当我们直接存一个大的对象的时候,比新生代占用空间还有大时,会直接晋升为老年代。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355