你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
输入关键字进行搜索
搜索:
没有找到相关结果
nccloud
jstat -gc 20756 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT CGC CGCT GCT 0.0 6144.0 0.0 4712.7 73728.0 0.0 57344.0 34393.5 61132.0 59888.7 7372.0 6980.1 19 0.172 0 0.000 6 0.019 0.191
S0C: survivor 0区域的容量,以KB为单位S1C: survivor 1区域的容量,以KB为单位S0U: survivor 0区域的使用大小,以KB为单位S1U: survivor 1区域的使用大小,以KB为单位EC: Eden区域的容量,以KB为单位EU: Eden区域的使用,以KB为单位MC: Metaspace元数据区的 Committed Size,以KB为单位MU: Metaspace元数据区的使用大小,以KB为单位CCSC: Compressed class的Committed Size,以KB为单位CCSU: Compressed class的使用大小,以KB为单位OC: old区域的容量,以KB为单位OU: old区域的使用,以KB为单位YGC: young generation(年轻代)的GC次数YGCT: young generation(年轻代)的GC消耗时间FGC: full GC的次数FGCT: full GC的消耗时间CGC: 并发GC次数(G1 gc)CGCT: 并发GC的消耗时间(G1 gc)GCT: GC总消耗时间
gccause:显示最近一次gc的原因
jstat -gccause 20756 S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT LGCC GCC 0.00 76.70 52.78 59.98 97.97 94.68 19 0.172 0 0.000 6 0.019 0.191 G1 Evacuation Pause No GC
S0: survivor 0区域的使用比例S1: survivor 1区域的使用比例E: Eden区域的使用比例O: Old区域的使用比例M: 元数据区域的使用比例CCS: Compressed class空间的使用比例YGC: young generation(年轻代)的GC次数YGCT: young generation(年轻代)的GC消耗时间FGC: full GC的次数FGCT: full GC的消耗时间CGC: 并发GC次数(G1 gc)CGCT: 并发GC的消耗时间(G1 gc)GCT: GC总消耗时间LGCC: 上次GC的原因GCC: 当前GC的原因
gcnew:新生代的统计信息
jstat -gcnew 20756 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 0.0 6144.0 0.0 4712.7 15 15 5120.0 73728.0 57344.0 19 0.172
S0C: survivor 0区域的容量
jstat -gcold 20756 MC MU CCSC CCSU OC OU YGC FGC FGCT CGC CGCT GCT 61132.0 59888.7 7372.0 6980.1 57344.0 34393.5 19 0 0.000 6 0.019 0.191
MC: Metaspace元数据区的 Committed Size,以KB为单位MU: Metaspace元数据区的使用大小,以KB为单位CCSC: Compressed class的Committed Size,以KB为单位CCSU: Compressed class的使用大小,以KB为单位OC: old区域的容量,以KB为单位OU: old区域的使用,以KB为单位YGC: young generation(年轻代)的GC次数FGC: full GC的次数FGCT: full GC的时间CGC: 并发GC次数(G1 gc)CGCT: 并发GC的消耗时间(G1 gc)GCT: 总的GC时间
gcmetacapacity:统计元数据区域的容量信息
jstat -gcmetacapacity 20756 MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT CGC CGCT GCT 0.0 1103872.0 61132.0 0.0 1048576.0 7372.0 19 0 0.000 6 0.019 0.191
MCMN: 最小metaspace大小MCMX: 最大metaspace大小MC: Metaspace元数据区的 Committed SizeCCSMN: Compressed class空间的最小容量CCSMX: Compressed class空间的最大容量CCSC: Compressed class的Committed SizeYGC: young generation的GC次数FGC: full GC的次数FGCT: full GC的时间CGC: 并发GC次数(G1 gc)CGCT: 并发GC耗时 (G1 gc)GCT: 总的GC时间
关于JVM,也许你听过这些术语:年轻代(新生代)、老年代、永久代、minor gc(young gc)、major gc、full gc
不要急,先上图,这是jvm 堆内存结构图
仔细的你发现了 图中有些分数8/10和1/10,这是默认配置下各个代内存分配比例。
举个栗子:
假如总heap max分配1200M,那么年轻代占用1/3就是400M,老年代占2/3就是800M。
Eden占年轻代的8/10就是320M。Survivor占年轻代的2/10就是80M,from和to各占40M。
年轻代也叫新生代,顾名思义,主要是用来存放新生的对象。新生代又细分为 Eden区、SurvivorFrom区、SurvivorTo区。
新创建的对象都会被分配到Eden区(如果该对象占用内存非常大,则直接分配到老年代区), 当Eden区内存不够的时候就会触发MinorGC(Survivor满不会引发MinorGC,而是将对象移动到老年代中),
在Minor GC开始的时候,对象只会存在于Eden区和Survivor from区,Survivor to区是空的。
Minor GC操作后,Eden区如果仍然存活(判断的标准是被引用了,通过GC root进行可达性判断)的对象,将会被移到Survivor To区。而From区中,对象在Survivor区中每熬过一次Minor GC,年龄就会+1岁,当年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置,默认是15)的对象会被移动到年老代中,否则对象会被复制到“To”区。经过这次GC后,Eden区和From区已经被清空。
“From”区和“To”区互换角色,原Survivor To成为下一次GC时的Survivor From区, 总之,GC后,都会保证Survivor To区是空的。
奇怪为什么有 From和To,2块区域?这就要说到新生代Minor GC的算法了:复制算法
把内存区域分为两块,每次使用一块,GC的时候把一块中的内容移动到另一块中,原始内存中的对象就可以被回收了,
优点是避免内存碎片。
老年代随着Minor GC的持续进行,老年代中对象也会持续增长,导致老年代的空间也会不够用,最终会执行Major GC(MajorGC 的速度比 Minor GC 慢很多很多,据说10倍左右)。Major GC使用的算法是:标记清除(回收)算法或者标记压缩算法。
标记清除(回收):1. 首先会从GC root进行遍历,把可达对象(存过的对象)打标记
2. 再从GC root二次遍历,将没有被打上标记的对象清除掉。
优点:老年代对象一般是比较稳定的,相比复制算法,不需要复制大量对象。之所以将所有对象扫描2次,看似比较消耗时间,其实不然,是节省了时间。举个栗子,数组 1,2,3,4,5,6。删除2,3,4,如果每次删除一个数字,那么5,6要移动3次,如果删除1次,那么5,6只需移动1次。
缺点:这种方式需要中断其他线程(STW),相比复制算法,可能产生内存碎片。
标记压缩:和标记清除算法基本相同,不同的就是,在清除完成之后,会把存活的对象向内存的一边进行压缩,这样就可以解决内存碎片问题。
当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。
永久代(元空间) 在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间,Metaspace)的区域所取代。
值得注意的是:元空间并不在虚拟机中,而是使用本地内存(之前,永久代是在jvm中)。这样,解决了以前永久代的OOM问题,元数据和class对象存在永久代中,容易出现性能问题和内存溢出,毕竟是和老年代共享堆空间。java8后,永久代升级为元空间独立后,也降低了老年代GC的复杂度。
Visual GC插件
自己不妨写点代码,测试下上面说过的GC过程,通过Visual GC插件
Java VisualVM安装Visual GC插件
https://blog.csdn.net/yujianping_123/article/details/99549194
面说到了minor gc 和major gc,那么看下full gc
Full GC
是清理整个堆空间—包括年轻代和老年代。
什么时候触发:
1. 调用System.gc
2. 方法区空间不足
2.老年代空间不足,包括:
新创建的对象都会被分配到Eden区,如果该对象占用内存非常大,则直接分配到老年代区,此时老年代空间不足做minor gc操作前,发现要移动的空间(Eden区、From区向To区复制时,To区的内存空间不足)比老年代剩余空间要大,则触发full gc,而不是minor gc等等GC优化的本质,也是为什么分代的原因:减少GC次数和GC时间,避免全区扫描。
1.对象不用时最好显式置为 Null一般而言,为 Null 的对象都会被作为垃圾处理,所以将不用的对象显式地设为 Null,有利于 GC 收集器判定垃圾,从而提高了 GC 的效率。
2.尽量少用 System.gc()此函数建议JVM 进行主GC,虽然只是建议而非一定,但很多情况下它会触发主 GC,从而增加主 GC 的频率,也即增加了间歇性停顿的次数。
3.尽量少用静态变量 静态变量属于全局变量,不会被 GC 回收,它们会一直占用内存。
4.尽量使用 StringBuffer, 而不用String 来累加字符串。由于 String 是固定长的字符串对象,累加 String 对象时,并非在一个 String对象中扩增,而是重新创建新的 String 对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的 String 对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用 StringBuffer 来累加字符串,因 StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。
5.分散对象创建或删除的时间集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM 在面临这种情况时,只能进行主 GC,以回收内存或整合内存碎片,从而增加主 GC 的频率。
集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主 GC 的机会。
6.尽量少用 finalize 函数。因为它会加大 GC 的工作量,因此尽量少用finalize 方式回收资源。
7.如果需要使用经常用到的图片,可以使用软引用类型,它可以尽可能将图片保存在内存中,供程序调用,而不引起 OutOfMemory。
8.能用基本类型如 int,long,就不用 Integer,Long 对象基本类型变量占用的内存资源比相应包装类对象占用的少得多,如果没有必要,最好使用基本变量。
9.增大-Xmx
要回复问题请先登录或注册
2 个回复
nccloud
S0C: survivor 0区域的容量,以KB为单位
S1C: survivor 1区域的容量,以KB为单位
S0U: survivor 0区域的使用大小,以KB为单位
S1U: survivor 1区域的使用大小,以KB为单位
EC: Eden区域的容量,以KB为单位
EU: Eden区域的使用,以KB为单位
MC: Metaspace元数据区的 Committed Size,以KB为单位
MU: Metaspace元数据区的使用大小,以KB为单位
CCSC: Compressed class的Committed Size,以KB为单位
CCSU: Compressed class的使用大小,以KB为单位
OC: old区域的容量,以KB为单位
OU: old区域的使用,以KB为单位
YGC: young generation(年轻代)的GC次数
YGCT: young generation(年轻代)的GC消耗时间
FGC: full GC的次数
FGCT: full GC的消耗时间
CGC: 并发GC次数(G1 gc)
CGCT: 并发GC的消耗时间(G1 gc)
GCT: GC总消耗时间
gccause:显示最近一次gc的原因
S0: survivor 0区域的使用比例
S1: survivor 1区域的使用比例
E: Eden区域的使用比例
O: Old区域的使用比例
M: 元数据区域的使用比例
CCS: Compressed class空间的使用比例
YGC: young generation(年轻代)的GC次数
YGCT: young generation(年轻代)的GC消耗时间
FGC: full GC的次数
FGCT: full GC的消耗时间
CGC: 并发GC次数(G1 gc)
CGCT: 并发GC的消耗时间(G1 gc)
GCT: GC总消耗时间
LGCC: 上次GC的原因
GCC: 当前GC的原因
gcnew:新生代的统计信息
S0C: survivor 0区域的容量
S1C: survivor 1区域的容量S0U: survivor 0区域的使用大小,以KB为单位
S1U: survivor 1区域的使用大小,以KB为单位
TT: Tenuring threshold(新生代晋升到老年代的阀值)
MTT: 最大的Tenuring threshold
DSS: 所需的survivor区大小
EC: Eden区域的容量
EU: Eden区域的使用,以KB为单位
YGC: young generation(年轻代)GC次数
YGCT: young generation(年轻代)GC所需的时间
MC: Metaspace元数据区的 Committed Size,以KB为单位
MU: Metaspace元数据区的使用大小,以KB为单位
CCSC: Compressed class的Committed Size,以KB为单位
CCSU: Compressed class的使用大小,以KB为单位
OC: old区域的容量,以KB为单位
OU: old区域的使用,以KB为单位
YGC: young generation(年轻代)的GC次数
FGC: full GC的次数
FGCT: full GC的时间
CGC: 并发GC次数(G1 gc)
CGCT: 并发GC的消耗时间(G1 gc)
GCT: 总的GC时间
gcmetacapacity:统计元数据区域的容量信息
MCMN: 最小metaspace大小
MCMX: 最大metaspace大小
MC: Metaspace元数据区的 Committed Size
CCSMN: Compressed class空间的最小容量
CCSMX: Compressed class空间的最大容量
CCSC: Compressed class的Committed Size
YGC: young generation的GC次数
FGC: full GC的次数
FGCT: full GC的时间
CGC: 并发GC次数(G1 gc)
CGCT: 并发GC耗时 (G1 gc)
GCT: 总的GC时间
nccloud
关于JVM,也许你听过这些术语:年轻代(新生代)、老年代、永久代、minor gc(young gc)、major gc、full gc
不要急,先上图,这是jvm 堆内存结构图
仔细的你发现了 图中有些分数8/10和1/10,这是默认配置下各个代内存分配比例。
举个栗子:
假如总heap max分配1200M,那么年轻代占用1/3就是400M,老年代占2/3就是800M。
Eden占年轻代的8/10就是320M。Survivor占年轻代的2/10就是80M,from和to各占40M。
年轻代
也叫新生代,顾名思义,主要是用来存放新生的对象。新生代又细分为 Eden区、SurvivorFrom区、SurvivorTo区。
新创建的对象都会被分配到Eden区(如果该对象占用内存非常大,则直接分配到老年代区), 当Eden区内存不够的时候就会触发MinorGC(Survivor满不会引发MinorGC,而是将对象移动到老年代中),
在Minor GC开始的时候,对象只会存在于Eden区和Survivor from区,Survivor to区是空的。
Minor GC操作后,Eden区如果仍然存活(判断的标准是被引用了,通过GC root进行可达性判断)的对象,将会被移到Survivor To区。而From区中,对象在Survivor区中每熬过一次Minor GC,年龄就会+1岁,当年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置,默认是15)的对象会被移动到年老代中,否则对象会被复制到“To”区。经过这次GC后,Eden区和From区已经被清空。
“From”区和“To”区互换角色,原Survivor To成为下一次GC时的Survivor From区, 总之,GC后,都会保证Survivor To区是空的。
奇怪为什么有 From和To,2块区域?
这就要说到新生代Minor GC的算法了:复制算法
把内存区域分为两块,每次使用一块,GC的时候把一块中的内容移动到另一块中,原始内存中的对象就可以被回收了,
优点是避免内存碎片。
老年代
随着Minor GC的持续进行,老年代中对象也会持续增长,导致老年代的空间也会不够用,最终会执行Major GC(MajorGC 的速度比 Minor GC 慢很多很多,据说10倍左右)。Major GC使用的算法是:标记清除(回收)算法或者标记压缩算法。
标记清除(回收):1. 首先会从GC root进行遍历,把可达对象(存过的对象)打标记
2. 再从GC root二次遍历,将没有被打上标记的对象清除掉。
优点:老年代对象一般是比较稳定的,相比复制算法,不需要复制大量对象。之所以将所有对象扫描2次,看似比较消耗时间,其实不然,是节省了时间。举个栗子,数组 1,2,3,4,5,6。删除2,3,4,如果每次删除一个数字,那么5,6要移动3次,如果删除1次,那么5,6只需移动1次。
缺点:这种方式需要中断其他线程(STW),相比复制算法,可能产生内存碎片。
标记压缩:和标记清除算法基本相同,不同的就是,在清除完成之后,会把存活的对象向内存的一边进行压缩,这样就可以解决内存碎片问题。
当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。
永久代(元空间)
在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间,Metaspace)的区域所取代。
值得注意的是:元空间并不在虚拟机中,而是使用本地内存(之前,永久代是在jvm中)。这样,解决了以前永久代的OOM问题,元数据和class对象存在永久代中,容易出现性能问题和内存溢出,毕竟是和老年代共享堆空间。java8后,永久代升级为元空间独立后,也降低了老年代GC的复杂度。
Visual GC插件
自己不妨写点代码,测试下上面说过的GC过程,通过Visual GC插件
Java VisualVM安装Visual GC插件
https://blog.csdn.net/yujianping_123/article/details/99549194
面说到了minor gc 和major gc,那么看下full gc
Full GC
是清理整个堆空间—包括年轻代和老年代。
什么时候触发:
1. 调用System.gc
2. 方法区空间不足
2.老年代空间不足,包括:
新创建的对象都会被分配到Eden区,如果该对象占用内存非常大,则直接分配到老年代区,此时老年代空间不足
做minor gc操作前,发现要移动的空间(Eden区、From区向To区复制时,To区的内存空间不足)比老年代剩余空间要大,则触发full gc,而不是minor gc
等等
GC优化的本质,也是为什么分代的原因:减少GC次数和GC时间,避免全区扫描。
如何减少GC出现的次数(GC优化)
1.对象不用时最好显式置为 Null
一般而言,为 Null 的对象都会被作为垃圾处理,所以将不用的对象显式地设为 Null,有利于 GC 收集器判定垃圾,从而提高了 GC 的效率。
2.尽量少用 System.gc()
此函数建议JVM 进行主GC,虽然只是建议而非一定,但很多情况下它会触发主 GC,从而增加主 GC 的频率,也即增加了间歇性停顿的次数。
3.尽量少用静态变量
静态变量属于全局变量,不会被 GC 回收,它们会一直占用内存。
4.尽量使用 StringBuffer, 而不用String 来累加字符串。
由于 String 是固定长的字符串对象,累加 String 对象时,并非在一个 String对象中扩增,而是重新创建新的 String 对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的 String 对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用 StringBuffer 来累加字符串,因 StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。
5.分散对象创建或删除的时间
集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM 在面临这种情况时,只能进行主 GC,以回收内存或整合内存碎片,从而增加主 GC 的频率。
集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主 GC 的机会。
6.尽量少用 finalize 函数。
因为它会加大 GC 的工作量,因此尽量少用finalize 方式回收资源。
7.如果需要使用经常用到的图片,可以使用软引用类型,它可以尽可能将图片保存在内存中,供程序调用,而不引起 OutOfMemory。
8.能用基本类型如 int,long,就不用 Integer,Long 对象
基本类型变量占用的内存资源比相应包装类对象占用的少得多,如果没有必要,最好使用基本变量。
9.增大-Xmx