今天在JAVA群里突然有人问了一个问题:
问个问题,我启动一个主线程一直sleep, 通过jconsole监控,几个小时过后,发现内存占用依旧缓慢在上涨,请问是什么导致的呢?
其实我之前也发现在排查JVM问题的时候,通过jvisualvm跟踪的时候也发现了这个问题,当时是一个web工程后,启动后,没有任何流量也没有任何定时任务,但是Eden区的内存一直在缓慢的涨,这是为什么呢?
JVM内部线程
首先要纠正的一点是,我们的java程序是允许在JVM上,即使我们的程序只有一个主线程,但是JVM是有众多的内部线程和我们的程序一起运行的,当然大部分是以后台方式运行,比如垃圾回收线程,Attach Listener线程,Finalizer线程,你可以从JVM 内部运行线程介绍中找到详细的介绍,我着重了解Attach Listener线程: 它是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。
猜测
从上面Attach Listener线程的描述我大胆推测,是因为我们使用了jconsole和jvisualvm连接了程序,而监控必然会调用JVM的各种命令,例如jstack, jstat,jmap,同时还通过JMX的接口来获取程序内部的状态,因此这些调用过程其实就新增了更多的内存占用。
验证
验证过程其实很简单,启动程序后,通过jps命令获取进程号,通过 jstat -gc pid 2000命令观察程序的Eden区占用是否有变化,通过一段时间的观察,非常的稳定,而在确定么有变化后,我使用jvisualvm连接正在运行的程序,此时观察jstat的结果,内存瞬间就增加了,验证了我上面的猜测。
结论
JAVA程序运行时除了我们程序本身新建的线程,还有JVM管理的各种后台线程,同事java还提供JMX的方式对外暴露程序内部的信息,而这些在运行过程中都会占用内存。
欢迎关注我的个人的博客www.zhijianliu.cn, 虚心求教,有错误还请指正轻拍,谢谢
版权声明:本文出自志健的原创文章,未经博主允许不得转载