手把手教你如何写出完美的JVM的Young GC
模拟JVM的Young GC
JVM参数示范(基于JDK 1.8)
用如下JVM参数运行代码:
# 初始新生代大小 5M
-XX:NewSize=5242880
# 最大新生代大小 5M
-XX:MaxNewSize=5242880
# 初始堆大小 10M
-XX:InitialHeapSize=10485760
# 最大堆大小 10M
-XX:MaxHeapSize=10485760
-XX:SurvivorRatio=8
# 大对象阈值是10MB
-XX:PretenureSizeThreshold=10485760
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
如何打印JVM GC日志?
GC日志打印选型:
-XX:+PrintGCDetils:打印详细gc日志-XX:+PrintGCTimeStamps:这个参数可以打印出来每次GC发生的时间-Xloggc:gc.log:这个参数可以设置将gc日志写入一个磁盘文件
加上该参数后,JVM参数如下:
-XX:NewSize=5242880
-XX:MaxNewSize=5242880
-XX:InitialHeapSize=10485760
-XX:MaxHeapSize=10485760
-XX:SurvivorRatio=8
-XX:PretenureSizeThreshold=10485760
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
实例
对象是如何分配在Eden
byte[] array1 = new byte[1024 * 1024];
该行会在JVM Eden内放入一个1M数组,同时在main线程的虚拟机栈压入一个main方法栈帧,其栈帧内部有一“arr1”变量,该变量指向Eden的那1M数组:
arr1 = new byte[1024 * 1024];
此时会在Eden创建第二个数组,局部变量指向其。然后第一个数组无人引用,成了垃圾:
byte[] array1 = new byte[1024 * 1024];
在Eden创建第三个数组,同时让arr1指向第三个数组,此时前两个数组都无人引用,都成了垃圾:
arr1 = null;
arr1啥都不指了,导致之前创建的3数组全部变成垃圾:
byte[] arr2 = new byte[2 * 1024 * 1024];
分配一个2MB大小的数组,尝试放入Eden,这时Eden放的下吗?
显然不行,Eden共4M,已放入3个1M数组,只剩1M,所以这时就会触发Y-GC。
采用指定JVM参数运行程序
然后运行即可,运行完后,会出现gc.log文件,即本次程序运行的gc日志:
打开gc.log文件,我们会看到如下所示的gc日志:
这次运行程序的JVM参数,包含:
我们自己手动设置的
默认的参数设置
给JVM加个打印gc日志的参数,就可以在此看到JVM默认参数配置
一次GC的路途
0.410: [GC (Allocation Failure) 0.410: [ParNew: 3863K->465K(4608K), 0.0025689 secs] 3863K->1491K(9728K), 0.0029347 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
0.269: [ParNew: 4030K->512K(4608K), 0.0015734 secs] 4030K->574K(9728K), 0.0017518 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
概要说明本次GC执行情况:
GC (Allocation Failure),看字面意思即可,为啥会发生一次GC呢?
因为要分配一个2M数组,但Eden内存不足,所以“Allocation Failure”,内存分配失败,所以就要触发一次Y-GC。
那这次GC何时发生?
看一个数字,“0.410”:你的系统运行后,过了多少s发生的本次GC,此处就是系统运行后的410ms发生了GC。
ParNew: 3863K->465K(4608K), 0.0025689 secs
此处触发的是Y-GC,所以用的也就是指定的ParNew来执行GC。
3863K->465K(4608K)
新生代可用空间4608KB,约4.5MB,Eden是4M,两个Survivor只有一个可放存活对象,另外一个必须保持空闲,所以年轻代可用空间是 Eden+1个Survivor=4.5MB。
3863K->465K:对年轻代执行一次GC,GC前使用了3863K,但GC后只有465K对象存活。
GC前,我们在Eden只放了3个1M数组,共3MB,即3072K,那为啥这里显示使用了3863K?
- 自定义创建的数组本身虽是1MB,但为存储该数组,JVM内置还会附带一些其它信息,所以每个数组实际占用的内存是大于1MB的
- 可能还有一些你看不见的对象在Eden里
所以GC前,三个数组+其他未知对象=3863K内存。GC前,我们在Eden只放了3个1M数组,共3MB,即3072K,那为啥这里显示使用了3863K?
- 自定义创建的数组本身虽是1MB,但为存储该数组,JVM内置还会附带一些其它信息,所以每个数组实际占用的内存是大于1MB的
- 可能还有一些你看不见的对象在Eden里
所以GC前,三个数组+其他未知对象=3863K内存。
0.0025689 secs:本次GC耗费时间,看这里来说大概耗费2.5ms,仅回收3MB对象而已。
3863K->1491K(9728K), 0.0029347 secs
整个Java堆内存的情况。整个Java堆内存总可用空间9728K(9.5M)=年轻代4.5MB+老年代5M。
- GC前,整个Java堆内存使用了3863K
- GC后Java堆内存使用了1491K
[Times: user=0.01 sys=0.00, real=0.01 secs]
本次gc消耗的时间,这里最小单位是小数点之后两位,单位是s。
图解GC执行过程
ParNew执行GC,回收掉自定义创建的三个数组,此时因为他们都无人引用,必成垃圾:
ParNew: 4030K->512K(4608K), 0.0015734 secs
gc回收后,从4030K内存使用降低到512K内存使用。即这次gc日志有512KB的对象存活,从Eden区转移到Survivor1区:
GC后的堆内存
Heap
par new generation total 4608K, used 2601K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000) eden space 4096K, 51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)from space 512K, 100% used [0x00000000ffa80000, 0x00000000ffb00000, 0x00000000ffb00000) to space 512K, 0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)concurrent mark-sweep generation total 5120K, used 62K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)Metaspace used 2782K, capacity 4486K, committed 4864K, reserved 1056768K class space used 300K, capacity 386K, committed 512K, reserved 1048576K
JVM退出时打印的当前堆内存使用情况
ParNew负责的新生代共4608K(4.5MB)可用内存,目前使用2630K(2.5MB)。此时在JVM退出前,为何新生代占了2.5M?GC后,通过如下代码又分配了个2M数组:
byte[] arr2 = new byte[2 * 1024 * 1024];
所以此时在Eden一定会有个 2M数组=2048K,然后上次GC后,在From Survivor存活了个512K未知对象,那么:
2048KB+512KB=2560KB2048KB + 512KB = 2560KB2048KB+512KB=2560KB
每个数组会额外占据一些内存存放一些自己这个对象的元数据,可认为多出来的70K是数组对象额外使用的内存空间。
Eden日志
Eden此时4M内存被用52%,就因为那2M数组。然后From Survivor区,512K是100%使用率,此时被之前GC后存活下来的512K未知对象占据。
CMS、Metaspace元数据空间和Class空间
Concurrent Mark-Sweep垃圾回收器,即CMS管理的老年代内存空间共5M,此时使用了62K。
Metaspace元数据空间和Class空间,存放一些类信息、常量池之类的东西,此时他们的总容量,使用内存等。
手把手教你如何写出完美的JVM的Young GC相关推荐
- 教你如何写出完美的论文——5. 做笔记
1. 做笔记的哲学解释 做研究=读, 做笔记=写 做笔记是关于深入思考你阅读的内容的含义,并且用一个办法将这个含义以清晰.准确.有用的形式应用在你将来的论文引用中.你的笔记必须完整.清晰.易理解.易读 ...
- larvel php restful_Laravel教你简单写出专业的RestfulAPI
下面由Laravel教程栏目给大家介绍Laravel写出专业的RestfulAPI的方法,希望对需要的朋友有所帮助! Laravel教你简单写出专业的URL 引言 在我们连接了数据库,并且使用迁移功能 ...
- 手把手第一篇:写出第一行 Hello World
如何在 iOS 或 Android 应用中写出第一行属于自己的 Hello World? 地球上最流行的移动操作系统,非苹果公司的 iOS 与谷歌公司的 Android 系统莫属了,那如何写出自己的第 ...
- 分式怎么开根号_怎么打出根号二(教你如何写出√2的连分式)
连有理数是数学课的一大闪光点,数学家欧拉将连分数的运用推到完美,并为此解决了很多数学题目,这篇大家就来科学研究一个比较简单的连有理数,即√2的连有理数,使你体会下它的数学课风采和本质规律性 最先√2相 ...
- 用案例说话,教你如何写出有吸引力的开发信以及主题
国际贸易往来,开发信必不可少,在我们发邮件之前,首先是设置开发信的主题和内容今天我来分享下我日常写开发信以及主题的一些经验,希望可以帮助到大家. 主题:"主题"是客户了解邮件的第一 ...
- 手把手教你如何写作美赛论文
本文结合网络上资源.个人建模经历.以及一系列书本而成,欢迎讨论和咨询 美赛写作的重要程度 由于美赛不提交代码,做的好不好和写的好不好完全决定了你拿奖的可能性. 该项赛事要求提交英文摘要和论文,作为评奖 ...
- 一篇文章教你如何写出【✨无法维护✨】的代码?
对,你没看错. 本文就是教你怎么写出让同事无法维护的代码. ❤️ 1.程序命名❤️ 容易输入的变量名.比如:Fred,asdf 单字母的变量名.比如:a,b,c,x,y,z(如果不够用,可以考虑 a1 ...
- 黑马程序员教你如何写出优秀的前端工程师简历
对于一名想找工作的前端开发工程师而言,简历直接关系到面试概率甚至薪资水平,其重要性已不用多说.在HR快速筛选简历的情况下,你的简历要脱颖而出,就得在短时间内将自己的亮点展示给招聘方.具体怎么做?黑马程 ...
- 国庆八天教你怎么写出一个钢琴
来源:听见下雨声 https://juejin.im/post/6879708939190009869 前言 国庆节八天来娱乐一下,教你怎么用代码写出一个钢琴????,并用它弹奏歌曲.学生时代的我们如 ...
最新文章
- FlameScope 更高级全面的火焰图
- ceph 部署单机集群
- runloop源代码
- java 微信退款接口_java版微信和支付宝退款接口
- mybatis-plus代码生成器简易使用
- Express接口案例——完成文章增删改查接口
- android外接键盘打汉字,Android在外接物理键盘时,如何强制调用系统软键盘
- Windows环境下hadoop安装和配置详细步骤
- d2j-dex2jar classes.dex报错
- TeamTalk源码分析(一)—— TeamTalk介绍
- 个人观点:苹果对iPad商标事件的解决办法
- 金融科技大数据产品推荐:恒丰银行实时智能决策引擎
- macbook air适合学java,神舟7月9日发轻薄笔记本新品 比MacBook Air还要薄?
- 量子计算机与新南威尔士大学,新南威尔士大学声称量子计算的准确性
- 大白菜 装系统 win7
- WordPress关注微信公众号回复可见和阅读更多的方法
- mysql sum提高效率_MySQL巧建sum索引帮我们提高至少100%的效率
- 金融量化-金叉和死叉
- 人工智能在物联网项目中的应用
- php 表单模板,迅睿CMS 网站表单模板
热门文章
- Python上手就有
- AIX系统更换本地硬盘
- Visual Studio 2017 卸载 以及 Visual Studio 2010 安装
- 贝叶斯网络学习总结与中科院…
- 解决ubuntu Certificate verification failed: The certificate is NOT trusted.
- 广州昊志,深圳爱贝科电主轴常用巴鲁夫BALLUAF电感式开关BES03Z8 、BES00FW 、BES00FT、BES00HJ参数
- Pidgin 上QQ
- XDOC支持Markdown格式了
- 如何在VB.NET中查询所有打印机端口名称,端口号ne
- 蓝宝石RX590gme白金刷580bios,完美解决