案例出于《深入理解Java虚拟机》第二版
场景
一个带心跳检测功能的GUI桌面程序,每15秒会发送一次心跳检测信号,如果对方30秒以内都没有信号返回,就认为和对方程序的连接已经断开。
问题
程序上线后发现心跳检测有误报的概念,查询日志发现误报的原因是程序会偶尔出现间隔约一分钟左右的时间完全无日志输出,出于停顿状态。
分析
- 因为是桌面程序,所需内存并不大(-Xmx 256MB),所以开始并没想到GC导致的程序停顿,但加入参数-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -Xloggc:gclog.log后,从GC日志文件中确认了停顿确实是由GC导致的,大部分GC时间都控制在100毫秒,但偶尔会出现接近1分钟的GC。
- 从GC日志中知道长时间停顿的具体日志信息(添加-XX:+PrintReferenceGC参数),找到日志片段,可看出真正执行GC动作的时间不是很长,但从准备开始GC,到真正开始GC之间所消耗的时间却占了绝大部分。
- 除GC日志之外 ,还观察到GUI程序内存变化的一个特点,当它最小化的时候,资源管理中显示的占用内存大幅度减少,但虚拟内存则没有变化,因此怀疑程序在最小化时它的工作内存被自动交换到磁盘的页面文件之中,这样发生GC时就有可能因为恢复页面文件的操作而导致不正常的GC停顿。
- 解决方案
在Java的GUI程序中要避免这种现象,可加入参数“-Dsun.awt.keepWorkingSetOnMinimize=true”来解决。
网友评论