java程序的gc
java有自己的内存管理和垃圾回收机制(gc),依赖jvm实现
jvm的gc算法是基于如下概念的:
1、 内存分区,年轻代(eden, survior), 老年代(old)。这些说的都是堆内存
2、younggc,程序new出来的对象出来的先放eden, 放不下了执行一次young gc, eden清空,原来eden里的放到到survior; survior里也快满了的话,younggc会把这些对象转存到old区。可以理解为younggc除了释放内存,还做很多转存的工作
3、full gc,终极gc,耗时长,期间程序阻塞。old区快满了,fullgc释放内存
java程序启动参数,可以设置堆内存大小,打印gc日志,改变内存区大小比例
4、gc日志截图
可以看到图中的一次full gc后, 堆内存变大了。对应到用top监控进程的实存虚存,也会相应增大。 但是old区不够大,不一定是内存泄漏造成的,有可能是本身分配的不够。
5、不能使用monitor.sh或者top里监控到的java进程的实存虚存作为判断是否有内存问题的标准,即使监控到的值有上升,也无法说明有内存问题(可能是jvm重新分配了); 即使监控到的值很平稳,也可能是因为运行时间不足,导致内存泄漏的问题没有暴露出来(可能堆内存分配的较大,虽有增长,但还够用。但更长时间的运行,最终还是会保留问题。这个和c/c++的不一样,因为只要压测覆盖到相应new对象的代码,程序如果没free,那理论上就能观测到内存增长)
6、java进程内存监控方法
方法一:(推荐)进程启动时开启gc log,使用已有的filebeat解析gc log的配置文件, 使用efk观测堆内存占用曲线
方法二:使用jvisualm(有点是有图)或者jconsole(有点是jdk或jre自带)等图形化工具,监控java进程相关信息(不止gc)
7、总结
(1)压测java程序必须监控gc后的堆内存的使用情况。 直接监控实存虚存无效
(2)full gc不宜太频繁,单次耗时可能也不宜太长
(3)启动java进程时,很可能需要修改启动参数(内存大小配置、gc log配置)