因此,一个进程的实际内存永远不会减少。提醒我的是一篇文章,Java的Runtime是用C/C++编写的,所以我想应该也适用于Java?
更新:我的问题是关于Java的。我提到C/C++,因为我假设Java的分配/释放是由JRE使用某种malloc/delete形式完成的。
HotSpot JVM 会将内存释放回操作系统,但它不太愿意这样做,因为调整堆大小是昂贵的,而且如果你曾经需要过这个堆,就会认为你将再次需要它。
一般来说,收缩能力和行为取决于选择的垃圾收集器、JVM 版本,因为缩小能力通常是在稍后的版本中引入的,在添加 GC 本身之后很长时间。有些收集器可能还需要传递其他选项以选择缩小。而有些则很可能永远不支持,例如 EpsilonGC。因此,如果需要堆缩小,应该针对特定的 JVM 版本和 GC 配置进行测试。
这些版本没有明确的即时内存回收选项,但您可以通过设置 -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30
让 GC 更加积极地回收内存,并在 GC 循环后限制已分配但未使用的堆内存量。
-XX:InitiatingHeapOccupancyPercent=N
,其中N为较低的值,以使GC几乎持续进行并发收集,这将消耗更多CPU周期但更快地缩小堆。这通常不是一个好主意,但对于某些具有大量空余CPU核心但内存不足的机器类型可能是有意义的。-XX:+PrintAdaptiveSizePolicy
,这也可能提供见解,例如当JVM尝试使用更多内存来满足一些目标时。
添加了-XX:-ShrinkHeapInSteps
选项,可以更积极地应用前面提到的选项引起的收缩。相关OpenJDK bug。
对于日志记录,-XX:+PrintAdaptiveSizePolicy
已被-Xlog:gc+ergo
替换。
通过G1PeriodicGCInterval
(JEP 346)引入了启用G1GC的及时内存释放选项,但会牺牲一些额外的CPU。该JEP还提到了Shenandoah和OpenJ9 VM中的类似功能。
添加类似于ZGC的行为,但此时默认情况下启用。此外,XXSoftMaxHeapSize
对于某些工作负载可能有所帮助,使平均堆大小保持在某个阈值以下,同时仍允许瞬态峰值。
JVM(Java虚拟机)在某些情况下确实会释放内存,但出于性能考虑,当某些内存被垃圾回收时,并不总是发生释放。这还取决于JVM、操作系统、垃圾收集器等因素。您可以使用JConsole、VisualVM或其他分析工具观察应用程序的内存消耗。
此外,请参阅相关的错误报告
如果您使用G1收集器并偶尔调用System.gc()(我每分钟调用一次),Java会可靠地缩小堆并将内存归还给操作系统。
自Java 12以来,如果应用程序处于空闲状态,G1会自动执行此操作。
我建议结合上述建议使用这些选项以获得非常紧凑的驻留进程大小:
-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10
我使用这些选项已经几个月了,它们与大型应用程序(一个基于Java的客户操作系统)一起使用,可以动态地加载和卸载类 - Java进程几乎总是保持在400到800 MB之间。
@
标记我,否则我不知道你在回复什么 2)Xms
不是最小内存,而是初始内存,因此你是错误的。 - Eugene-Xms
的文档上,现在越来越多的人(包括开发GC的人)说它是最小堆值? - MatthieuInitialHeapSize
,这使得情况更加混乱。 - Eugene简短回答:内存会根据垃圾收集器的配置(算法)立即或稍后返回给操作系统。
如果您使用的是JDK 8或更早版本,并运行以下代码片段:
public static void main(String[] args) throws InterruptedException {
Runtime runtime = Runtime.getRuntime();
long availableMemory = runtime.freeMemory();
System.out.println("Initially Available Memory : " + availableMemory);
List<Customer> customers = new ArrayList<>();
for (int loop = 0; loop < 1_00_000; loop++) {
customers.add(new Customer("USERNAME"));
}
availableMemory = runtime.freeMemory();
System.out.println("Post Processing Available Memory : " + availableMemory);
customers= new ArrayList<>();
Thread.sleep(1000);
System.gc();
availableMemory = runtime.freeMemory();
System.out.println("Post Garbage Collecting Available Memory : " + availableMemory);
}
Initially Available Memory : 243620776
Post Processing Memory : 240444976
Post Garbage Collecting Memory : 250960720
System.gc()
时,我们会得到空闲内存,并且JVM接收它并不将其返回给操作系统。
当运行相同的代码片段时,我们得到了一个令人惊讶的结果:
Initially Available Memory: 242021048
Post Processing Memory: 239171744
Post Garbage Collecting Memory: 61171920
System.gc()
时,JVM会释放内存并将其返回给操作系统。-Xms
来设置初始堆大小。$ java -Xms2g MyProgram.java
Initially Available Memory : 2124414976
Post Processing Memory : 2120842392
Post Garbage Collecting Memory : 2144444600