java.exe进程使用更多内存并且不释放它

我有一个java应用程序,在任何复杂执行之前处于空闲状态时,在Heap中使用23 MB并且TaskManager中的java.exe进程大小约为194 MB。 经过一些复杂的操作后,java.exe的大小增长到大约500MB,堆大小也随之增长。 通过调用System.gc()方法,在几个完整的GC之后,堆大小减少到23MB。 但java.exe的大小从大约600MB减少到大约237MB,其中仍然有大约43 MB的数据。 有没有办法减少这个? 或者是由于某些行为?

这很正常,不用担心。 JVM在需要执行某些复杂逻辑时获取内存。 当java完成处理任务时,JVM仍将该内存保留为保留空间,并且不会释放回操作系统。 此体系结构有助于提高性能,因为JMV不必再从底层操作系统请求相同的内存。 它仍然在您在-Xmx JVM参数中定义的范围内。

有关一些有趣的细节,请参阅此IBM链接。 http://www-01.ibm.com/support/docview.wss?uid=swg21326774

不幸的是,这是JVM的灰色区域之一; 你真的没有太多关于OS和JVM如何在彼此之间共享内存的控制。 将JVM视为需要运行一些内存的虚拟操作系统。 您的父操作系统和虚拟机都渴望获得资源,并且希望尽可能多地将所获取的资源挂在所获取的资源上。 从操作系统请求更多内存是一项耗时的操作,因此大多数JVM都不会将内存释放回操作系统,即使它们不再需要它也是如此。

有关内部JVM内存管理的更多详细信息,请参阅Oracle的此白皮书。 http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf

我建议你先阅读IBM链接,然后你可以深入研究白皮书中解释的奇怪的内存世界。 这两个链接都非常有用且有趣。

java进程的OS足迹由

  • java堆(它的大小受-Xmx限制)
  • java类相关的元数据(或HotSpot JVM中的永久生成)
  • 通过NIO可访问的非堆内存
  • 用于java线程的堆栈空间

一些垃圾收集算法将空闲内存返回给OS,其他则没有。 在HotSpot JVM中,串行旧空间收集器(通常默认启用)将内存返回到OS(因此您可以看到进程收缩)。 但是,其他收集器如-XX:+UseParallelOldGC-XX:+UseConcMarkSweepGC将永远不会将未使用的堆内存返回给OS。

HotSpot JVM具有管理/限制上述所有内存区域的选项,您可以在我的博客中找到与内存大小调整和GC调整相关的JVM选项的完整列表。