转载

【JVM命令及问题排查】

java中的gc log解读

eclipse的优化 gc.log

一次让人难以忘怀的排查频繁Full GC过程

一个GC频繁的Case

堆内存占用很小 但是 JVM 频繁full gc 问题排查

JVM中GC时,堆内存是如何动态变化的(JDK1.7)

使用jmap和MAT分析JVM堆内存

Jmap+MAT 排查内存泄漏

关于内存溢出

Young(Nursery) :年轻代

Old(Tenured) :年老代

Permanent(Perm) :持久代

装载Class信息等基础数据

堆设置 

-Xms:初始堆大小 ,默认是物理内存的1/64

-Xmx:最大堆大小 

-Xmn:年轻代大小

-Xss:jvm启动的每个线程分配的内存大小

-XX:NewSize=n:设置年轻代大小 

-XX:PermSize=64m设置持久代大小

-XX:MaxPermSize=n:设置持久代最大大小

MaxPermSize过小会导致:java.lang.OutOfMemoryError: PermGen space

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 

-XX:MaxTenuringThreshold 

如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

-Xmx512m: (max)堆最大可用内存为512M。

-Xms512m: (small)堆最小内存为512m。

此值可以设置与-Xmx最大值相同,以避免每次垃圾回收完成后JVM动态调节Java堆大小而耗费延长其周期。 

-Xmn192m :(new)设置年轻代大小为192m。

整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

垃圾回收统计信息 

-XX:+PrintGC 

-XX:+PrintGCDetails 

-XX:+PrintGCTimeStamps 

-Xloggc:filename

-XX:+PrintGC 

输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] 

[Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails 

输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] 

[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用 

输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]

默认java程序是不会开启gc log

对于生产环境下的java程序可以加上来生成gc log,方便出现问题的时候去排查

-verbose:gc -Xloggc:/usr/gclog -XX:+PrintGCDetails XX:+PrintGCTimeStamps

收集器设置 

-XX:+UseSerialGC:设置串行收集器 

-XX:+UseParallelGC:设置并行收集器 

-XX:+UseParalledlOldGC:设置并行年老代收集器 

-XX:+UseConcMarkSweepGC:设置并发收集器

-XX:+DisableExplicitGC这个将会忽略手动调用GC的代码使得 System.gc()的调用就会变成一个空调用,完全不会触发任何GC。

======================================================================

java中的gc log解读

https://my.oschina.net/hadooper/blog/418918

eclipse的优化 gc.log

https://blog.csdn.net/z69183787/article/details/39136119

默认java程序是不会开启gc log

对于生产环境下的java程序可以加上来生成gc log,方便出现问题的时候去排查

-verbose:gc -Xloggc:/usr/gclog -XX:+PrintGCDetails XX:+PrintGCTimeStamps

Linux如何开启tomcat的gc日志并查看

进入到了tomcat的bin的目录下中,命令中vi catalina.sh  来编辑

然后在该文件中cygwin=false上面

添加为

JAVA_OPTS="-Xms128m -Xmx256m -Xmn100m -XX:MaxPermSize=30m -Xloggc:/usr/local/tomcat/logs/gc.$$.log"

gc开启完成之后,只要启动了tomcat之后,就可目录下生成了gc的log的日志内容。

场景一:

[GC [DefNew: 3298K->149K (5504K) , 0.0053498 secs] 3298K->3221K( 9600K ), 0.0053750 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

看一下这行:

DefNew表示新生态:3298K->149K(5504K), 0.0053498 secs

表示新生态由3298K回收变成了149K,即之前的3M回收了, 【5504K表示该区域的总内存大小】

3298K->3221K(9600K), 0.0053750 secs] 表示整个jvm堆的大小由于没有可以回收的对象,所以总大小本质没发生改变, 9600K是java的总堆大小9600K 。(虽然分配10M,其中还有持久态等其他内存区域)

[Times: user=0.00 sys=0.00, real=0.01 secs] 表示gc所花费的系统资源

场景二:

0.209: [GC 0.209: [DefNew: 4416K->511K( 4928K ), 0.0034707 secs] 4416K->614K(15872K), 0.0035239 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]  

6.383: [GC 6.383: [DefNew: 18880K->1985K( 21184K ), 0.0055311 secs] 46992K->30098K(68040K), 0.0055694 secs]

这6秒中GC日志打了69次, 而内存回收率还是蛮高的 young区18880-1985=16895 jvm 46992-30098=16894 都快接近100%了, 可以看出young区是由小到大在不断调整大小,所以不断GC,因此设一个初始值 吧,据说设置heap的1/4比较好,那就是 128M,所以eclipse.ini加入 

-Xmn128m

场景三:

103.759: [Full GC ( System ) 103.759: [Tenured: 81882K->66784K(393216K), 0.3287387 secs] 185350K->66784K(511232K), [Perm : 53464K->53414K(65536K)], 0.3287897 secs] [Times: user=0.33 sys=0.00, real=0.33 secs]

仔细观察日志,发现Full GC (System) 字样,这个意思是 eclipse里调用了System.gc()手动触发了系统GC ,在eclipse.ini里加入: 

-XX:+DisableExplicitGC

-XX:+DisableExplicitGC这个将会忽略手动调用GC的代码使得 System.gc()的调用就会变成一个空调用,完全不会触发任何GC。

======================================================================

关于内存溢出

https://blog.csdn.net/bbaiggey/article/details/50885943

第一类内存溢出,也是大家认为最多,第一反应认为是的内存溢出,就是堆栈溢出:

那什么样的情况就是堆栈溢出呢?当你看到下面的关键字的时候它就是堆栈溢出了:

java.lang.OutOfMemoryError: ......java heap space.....

也就是当你看到heap相关的时候就肯定是堆栈溢出了,此时如果代码没有问题的情况下, 适当调整-Xmx和-Xms是可以避免的 ,不过一定是代码没有问题的前提,为什么会溢出呢,要么代码有问题,要么访问量太多并且每个访问的时间太长或者数据太多,导致数据释放不掉,因为垃圾回收器是要找到那些是垃圾才能回收,这里它不会认为这些东西是垃圾,自然不会去回收了;主意这个溢出之前,可能系统会提前先报错关键字为:

java.lang.OutOfMemoryError:GC over head limit exceeded

这种情况是当系统处于高频的GC状态,而且回收的效果依然不佳的情况,就会开始报这个错误,这种情况一般是产生了很多不可以被释放的对象,有可能是引用使用不当导致,或申请大对象导致,但是java heap space的内存溢出有可能提前不会报这个错误,也就是可能内存就直接不够导致,而不是高频GC.

第二类内存溢出,PermGen的溢出,或者PermGen 满了的提示,你会看到这样的关键字:

关键信息为:

java.lang.OutOfMemoryError: PermGen space

原因:系统的代码非常多或引用的第三方包非常多、或 代码中使用了大量的常量、或通过intern注入常量、或者通过动态代码加载等方法,导致常量池的膨胀 ,虽然JDK 1.5以后可以通过设置对永久带进行回收,但是我们希望的是这个地方是不做GC的,它够用就行,所以一般情况下今年少做类似的操作,所以 在面对这种情况常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。

第三类内存溢出:在使用ByteBuffer中的allocateDirect()的时候会用到,很多javaNIO的框架中被封装为其他的方法

溢出关键字:

java.lang. OutOfMemoryError: Direct buffer memory

如果你在直接或间接使用了ByteBuffer中的allocateDirect方法的时候,而不做clear的时候就会出现类似的问题,常规的引用程序IO输出存在一个内核态与用户态的转换过程,也就是对应直接内存与非直接内存,如果常规的应用程序你要将一个文件的内容输出到客户端需要通过OS的直接内存转换拷贝到程序的非直接内存(也就是heap中),然后再输出到直接内存由操作系统发送出去,而直接内存就是由OS和应用程序共同管理的,而非直接内存可以直接由应用程序自己控制的内存,jvm垃圾回收不会回收掉直接内存这部分的内存,所以要注意了哦。

如果经常有类似的操作,可以考虑设置参数:-XX:MaxDirectMemorySize

第四类内存溢出错误:

溢出关键字:

java.lang. StackOverflowError

这个参数直接说明一个内容, 就是-Xss太小了 ,我们申请 很多局部调用的栈针等内容是存放在用户当前所持有的线程中的 ,线程在jdk 1.4以前默认是256K,1.5以后是1M,如果报这个错,只能说明-Xss设置得太小,当然有些厂商的JVM不是这个参数,本文仅仅针对Hotspot VM而已;不过在有必要的情况下可以对系统做一些优化,使得-Xss的值是可用的。

原文  http://uule.iteye.com/blog/2429062
正文到此结束
Loading...