我正在尝试在 Java 中处理正确的内存使用和垃圾收集。我无论如何都不是一个新手程序员,但在我看来,一旦 Java 触及某些内存,它就永远不会被释放以供其他应用程序使用。在这种情况下,您必须确保您的峰值内存永远不会太高,否则您的应用程序将继续使用任何峰值内存使用量。
我写了一个小示例程序试图证明这一点。它基本上有 4 个按钮...
- 填充类范围变量
BigList = new ArrayList<string>()
包含大约 25,000,000 个长字符串项。 - 调用
BigList.clear()
- 重新分配列表 -
BigList = new ArrayList<string>()
再次(缩小列表大小) - 调用
System.gc()
- 是的,我知道这并不意味着 GC 会真正运行,但这就是我们所拥有的。
接下来我在 Windows、Linux 和 Mac OS 上进行了一些测试,同时使用默认任务监视器检查进程报告的内存使用情况。这是我发现的...
- Windows - 抽列表,调用 clear,然后调用 GC 几次,根本不会减少内存使用。但是,使用
new
重新分配列表然后多次调用 GC 会将内存使用量降低到起始水平。 IMO,这是可以接受的。 - Linux(我将 Mint 11 发行版与 Sun JVM 一起使用)- 结果与 Windows 相同。
- Mac OS - 我遵循了与上述相同的步骤,但即使重新初始化对 GC 的列表调用似乎也没有效果。即使我的内存中没有任何内容,该程序仍将占用数百 MB 的 RAM。
谁能给我解释一下?有人告诉我一些关于“堆”内存的东西,但我仍然不完全理解它,我不确定它是否适用于此。据我所知,无论如何,我不应该看到我在 Windows 和 Linux 上的行为。
这只是 Mac OS Activity 监视器测量内存使用情况的方式不同,还是发生了其他事情?我宁愿不要让我的程序因大量 RAM 使用而闲置。感谢您的洞察力。
最佳答案
Sun/Oracle JVM 不会将不需要的内存返回给系统。如果你给它一个很大的最大堆大小,并且你实际上在某个时候使用了那个堆空间,JVM 不会把它还给操作系统用于其他用途。其他 JVM 会这样做(JRockit 曾经这样做过,但我认为它不再这样做了)。
因此,对于 Oracles JVM,您需要调整您的应用程序和系统以达到峰值使用率,这就是它的工作原理。如果您正在使用的内存可以使用字节数组进行管理(例如处理图像或其他内容),那么您可以使用映射字节缓冲区而不是 Java 字节数组。映射字节缓冲区直接取自系统,而不是堆的一部分。当您释放这些对象时(我相信它们是 GC'd,但不确定),内存将返回给系统。假设它甚至完全适用,您可能不得不使用它。
关于java - Java中的突发内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8265240/