今天看了下之前做的一个异步处理任务的服务,发现占用内存量比较大,达到2G,但我检查了代码,基本没有static对象。但这个服务有个特点,就是每次执行一个任务的时候,会从数据库中捞大量的数据做处理,因此我怀疑是因为有比较多的临时对象产生,但程序没有来的及释放。为了验证这个,我用了jinfo查看和临时设置启动参数,jmap查看内存占用情况和主动触发FGC,jstat查看gc情况,top查看整个程序占用的内存量。
用jmap查看,发现内存占用并没有那么高(free值很大),但capacity比较大。用top查看,整个程序也占用了接近2G,那既然free那么多,为啥程序还占用那么高的内存?是不是因为还没有gc导致?
因此我用jmap做了一次主动gc:/opt/jdk/bin/jmap -histo:live PID,看了top,还是一样大小,只是jmap出来的free值更高了(特别是老年代,新生代的used变成了0),说明gc是有起到作用的。但是,为啥top没有变化??
后来查了jmap出来的参数,MaxHeapFreeRatio参数的意思是,当空闲内存数超出这个值时,会回收内存直到最小内存。而我的程序里面,默认这个值是100,也就是说要所有内存都未使用才会释放(都100%未使用了还需要释放吗?没鸟用了)。为了验证,我用jinfo临时设置了参数:/opt/jdk/bin/jinfo -flag MaxHeapFreeRatio=70 PID,主动触发gc,发现top内存降到了1G。问题解决了。
网上有人遇到top出来的res结果和jmap查出来的结果不一致,具体原因我也没搞懂,但是,只要出发了gc,而且内存做了回收,结果应该跟top出来的结果是一致的。
但jinfo只是临时设置,为了程序每次启动都生效,必须在启动脚本中设置。这个是在gradle中。我的服务有个build.gradle文件,在里面加几个参数:
<pre style="font-family: Courier New; font-size: 12px; margin-bottom: 0px; margin-left: 22px; margin-right: 0px; margin-top: 0px; white-space: pre-wrap; word-wrap: break-word;">defaultJvmOpts = ["-XX:MaxHeapFreeRatio=70", "-XX:MaxTenuringThreshold=3", "-XX:MaxNewSize=1073741824"]</pre>
<pre style="background-color: transparent; color: rgb(0, 0, 0); font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 22px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; -webkit-text-stroke-width: 0px; white-space: pre-wrap; word-spacing: 0px; word-wrap: break-word;">MaxTenuringThreshold代表对象的被回收存活次数,</pre>
<pre style="background-color: transparent; color: rgb(0, 0, 0); font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 22px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; -webkit-text-stroke-width: 0px; white-space: pre-wrap; word-spacing: 0px; word-wrap: break-word;">MaxNewSize代表新生代内存大小。
执行build后自动生成启动脚本,搞定!
相关链接:
1、jvm启动参数
2、jstat使用
3、各种java工具
4、打印当前java的所有参数
5、jinfo设置参数
6、别人的例子(仅做参考)</pre>
网友评论