第一次简单的JVM学习

第一次简单的JVM学习

 

此次调试源于某一个Java进程貌似有内存泄露top命令查看内存发现:

启动时占用600M内存一天过去后涨到1.3G, 之后每天多涨200M, 到了几周后就到了峰值-Xmx4096m, 于是开始担心会不会这个应用跑着跑着outofmenory

 

这个Java进程的启动参数为:

java -server -Xms4096m -Xmx4096m -Xmn1280m 

-Dcom.sun.management.jmxremote.port=9910 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 

-Dserverbindport=8910 

-Denv_type=fat 

-Djava.io.tmpdir=/home/op1/DAS/das_hotel/tmp 

-Duser.dir=/home/op1/DAS/das_hotel 

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump_das_hotel_10.2.6.15.hprof 

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC 

-XX:CMSInitiatingOccupancyFraction=60 

-XX:CMSTriggerRatio=70 -XX:CMSTriggerPermRatio=70 

-Xloggc:/home/op1/DAS/das_hotel/logs/das_hotel_gc.log 

-XX:+PrintGCDateStamps 

-XX:+PrintGCDetails 

-classpath /home/op1/DAS/das_hotel/conf:/home/op1/DAS/das_hotel/lib/*: com.xxx.search.das.hotel.HotelDAS -t 2014-09-26-09-40-00

 

然后使用jstat -gc 查看发现FGC也就是FullGC次数是86,FGCT也就是FullGC时间消耗仅为3.

我一直以为FullGC是非常慢的,但看上去也很快一直不太了解原因.

后来查了下发现jstatFGC值在垃圾回收器是CMS的时候并不表示FullGC的次数而是表示stop-world的次数,CMS垃圾回收阶段, initial-markremark阶段会stopworld,从而增加计数.

 

如下面的log, 是一次把内存设为-Xmx1024m并重启后的CMS GC, 可以看到这两个时间段加起来正好是FGCT的值.

 

2014-09-26T10:02:38.811+0800: 1358.038: [GC [1 CMS-initial-mark: 364854K(720896K)] 382339K(1015808K), 0.0056400 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

2014-09-26T10:02:38.817+0800: 1358.044: [CMS-concurrent-mark-start]

2014-09-26T10:02:38.845+0800: 1358.072: [CMS-concurrent-mark: 0.028/0.028 secs] [Times: user=0.14 sys=0.01, real=0.02 secs]

2014-09-26T10:02:38.845+0800: 1358.072: [CMS-concurrent-preclean-start]

2014-09-26T10:02:38.848+0800: 1358.075: [CMS-concurrent-preclean: 0.003/0.003 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

2014-09-26T10:02:38.848+0800: 1358.075: [CMS-concurrent-abortable-preclean-start]

2014-09-26T10:02:39.150+0800: 1358.378: [CMS-concurrent-abortable-preclean: 0.108/0.302 secs] [Times: user=0.50 sys=0.01, real=0.30 secs]

2014-09-26T10:02:39.150+0800: 1358.378: [GC2014-09-26T10:02:39.150+0800: 1358.378: [ParNew: 275339K->8983K(294912K), 0.0058150 secs] 640193K->373840K(1015808K), 0.0059370 secs] [Times: user=0.04 sys=0.01, real=0.00 secs]

2014-09-26T10:02:39.157+0800: 1358.384: [GC[YG occupancy: 9253 K (294912 K)]2014-09-26T10:02:39.157+0800: 1358.384: [Rescan (parallel) , 0.0020850 secs]2014-09-26T10:02:39.159+0800: 1358.387: [weak refs processing, 0.0004540 secs]2014-09-26T10:02:39.159+0800: 1358.387: [scrub string table, 0.0006610 secs] [1 CMS-remark: 364856K(720896K)] 374110K(1015808K), 0.0036180 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]

2014-09-26T10:02:39.161+0800: 1358.388: [CMS-concurrent-sweep-start]

2014-09-26T10:02:39.456+0800: 1358.683: [GC2014-09-26T10:02:39.456+0800: 1358.683: [ParNew: 271127K->3980K(294912K), 0.0036940 secs] 467083K->199936K(1015808K), 0.0038920 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]

2014-09-26T10:02:39.536+0800: 1358.764: [CMS-concurrent-sweep: 0.371/0.376 secs] [Times: user=0.83 sys=0.01, real=0.38 secs]

2014-09-26T10:02:39.537+0800: 1358.764: [CMS-concurrent-reset-start]

2014-09-26T10:02:39.547+0800: 1358.774: [CMS-concurrent-reset: 0.010/0.010 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

 

/usr/java/jdk1.7.0_51/bin/jstat -gc 12564

S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT  

32768.0 32768.0  0.0   1137.2 262144.0 97978.6   720896.0   28112.1   33600.0 20245.5    339    2.581   2      0.009    2.591

 

也就是说这个应用并没有频繁地调用FullGC, 这点上说明至少它运行地尚可,没出问题(即使内存占用越来越多).

 

但我的根本目的是调查它会不会有outofmemory的可能性.

 

后来我强制调用了一次FullGC, 再用jmap查看发现新生代老生代的数据基本上都清空了.

也就是说当最悲观的情况下产生了FullGC, 也能把内存清理掉而不会引发outofmenory问题.

 

一些简单的总结:

CMS新生代的垃圾回收算法比较简单,并不会把所有未引用的对象全释放掉它仅仅会释放那些栈上的对象对于一些复杂引用对象如基于socket的网络连接和流之类的我猜测并不会在YoungGC释放(有待考证)

老生代内存占用到了一定比例就会触发CMS GC,性能也挺快的.

当遇到CMS GC时新生代又被放满了就会触发FullGC, 代价很大.

 

后记:

这是我第一次接触到JVM的东西感觉还是受益颇多.

如何理解Java的各个启动参数如何对gclog进行分析如何通过JVisualVM,JStat,JMap来对Java运行程序进行分析.

很多时候写代码稍微一个不注意,往往会对JVM的垃圾回收造成一定的影响所以需要在写代码的同时考虑到每行代码对JVM垃圾回收的影响.

 

突然有个想法:

对于C++的深入了解就是要知道每一行C++代码会被编译器怎么编译

对于Java的深入了解就是要知道每一行Java代码会被JVM怎么执行


 http://rednaxelafx.iteye.com/blog/1108768
http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html 

你可能感兴趣的:(第一次简单的JVM学习)