【发布时间】:2015-09-16 03:08:14
【问题描述】:
我目前正在开发一个 Java 应用程序并努力优化它的内存使用。据我所知,我正在遵循正确垃圾收集的准则。但是,我的堆似乎处于最大大小,尽管它不是必需的。
我的程序每小时运行一次资源密集型任务,此时计算机未有人使用。该任务使用了相当大的内存块,但在任务完成后立即将其全部释放。 NetBeans 分析器显示内存使用情况如下所示:
我真的很想在不使用时将所有堆空间还给操作系统。我没有理由在程序至少再过一个小时内什么都不做的情况下占用这一切。
这可能吗?谢谢。
【问题讨论】:
-
我认为这取决于您使用的 JVM。 JVM 规范对此只字未提,IIRC。
-
@Fakrudeen,你说的不正确。如果不按进程解除提交,操作系统可能会回收物理内存,但它需要先将内容写入磁盘,这会大大降低性能。对于许多服务器来说,它没有交换来确保它不会抖动。在这种情况下,操作系统永远无法回收内存,无论它多久未被触及。您的评论会误导之前没有上过操作系统课程的任何人。这是有害的。
-
@Fakrudeen,将未使用的内存交换到磁盘始终是个坏主意。写入磁盘时会产生 IO。更重要的是,如果 JVM 再次需要更多内存,它需要从磁盘读取垃圾内容。如果 JVM 可以缩小并避免被交换,那么如果它需要更多内存,它可以要求操作系统为它们分配空闲页面,这比从磁盘读取垃圾内容便宜得多。我很难过你们对交换的东西感觉很好。如果一个新手读到这个并且有一个终生的印象认为这不是什么大不了的事情被交换了怎么办。
-
@Fakrudeen,看看 OP 的图表,JVM 在他的资源密集型工作完成后进行 GC,JVM 肯定知道它使用了多少内存。我从不说 GC 不贵。我们说的问题不是 GC 是否昂贵,而是在 GC 之后,JVM 知道它有一堆空闲堆,但从不将其返回给 OS。伙计,我知道人们在受到批评时会本能地进行防御。但请考虑一下。另外,我想让新手知道交换是非常糟糕的事情。如果某个进程的磁盘 IO 很重,几乎所有其他进程都会挂起,例如你甚至不能通过 SSH 连接到机器。
-
最后,请注意,所有这些仅适用于 Java 的堆(即 GC 管理的内存)。从 GC 的角度来看,依靠交换来获取堆外内存(例如,
ByteBuffer.allocateDirect())绝对没有问题,并且可能完全可以接受(显然,取决于用例)。例如,所有主要的基于 Java 的数据库、缓存和搜索引擎都会这样做,尽管这些通常建议调整内存设置以避免匿名页面被换出。
标签: java memory-management heap-memory