Spring boot 当JVM空闲时将内存释放回操作系统

Spring boot 当JVM空闲时将内存释放回操作系统,spring-boot,garbage-collection,jvm,java-8,g1gc,Spring Boot,Garbage Collection,Jvm,Java 8,G1gc,我们有一个简单的微服务设置,基于SpringBoot和Windows服务器上的Java8 许多服务的负载较低,因为它们是各种外部合作伙伴的集成。所以他们大部分时间都是空闲的 问题是JVM只在触发垃圾收集时将内存释放回操作系统。因此,一个服务可能开始使用32mb,然后服务一个请求并分配2GB内存。如果该服务上没有其他活动,它将不会执行GC,服务器上的其他服务将受到影响 使用System.GC从外部或内部触发GC。GC工作正常,我已经知道如何使用-XX:MaxHeapFreeRatio和-XX:Mi

我们有一个简单的微服务设置,基于SpringBoot和Windows服务器上的Java8

许多服务的负载较低,因为它们是各种外部合作伙伴的集成。所以他们大部分时间都是空闲的

问题是JVM只在触发垃圾收集时将内存释放回操作系统。因此,一个服务可能开始使用32mb,然后服务一个请求并分配2GB内存。如果该服务上没有其他活动,它将不会执行GC,服务器上的其他服务将受到影响

使用System.GC从外部或内部触发GC。GC工作正常,我已经知道如何使用
-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio
-XX:+UseG1GC
控制堆何时应该扩展并释放内存到操作系统

我的问题是:当JVM空闲时,什么是确保将内存释放回操作系统的最佳方法?

一个想法是让服务监视器本身在空闲一段时间后触发System.gc EFT,但这可能会很棘手且容易出错。希望能有更好的建议

您可以通过运行该程序的X个实例进行复制。大约10个用户让我的8GB Windows机器放弃了

import java.util.*;

public class Load {
  public static void main(String[] args) throws Exception {
    alloc();
    Scanner s = new Scanner(System.in);
    System.out.println("enter to gc ");
    s.nextLine();
    System.gc();
    System.out.println("enter to exit");
    s.nextLine();
  }

  private static void alloc() {
    ArrayList<String[]> strings = new ArrayList<>();
    int max = 1000000;
    for (int i = 0; i < max; i++) {
      strings.add(new String[500]);
    }
  }
}
import java.util.*;
公共类负载{
公共静态void main(字符串[]args)引发异常{
alloc();
扫描仪s=新的扫描仪(System.in);
System.out.println(“进入gc”);
s、 nextLine();
gc();
System.out.println(“进入到退出”);
s、 nextLine();
}
私有静态void alloc(){
ArrayList字符串=新的ArrayList();
int max=1000000;
对于(int i=0;i
c:\>java-server-XX:+UseG1GC-Xms32m-Xmx2048m加载

编辑:这被标记为重复两次,但它不是链接问题的重复。第一个问题是2010年版本的同一个问题,但这个问题是关于为什么GC不将内存释放回操作系统(这在当时是不可能的)。另一个问题是关于基本的GC设置,我已经写过,我理解。我希望讨论在系统空闲时如何触发垃圾收集器。因此,每五秒钟运行一次System.gc是不可接受的,因为这样会有与有效请求发生冲突并破坏响应时间的高风险

如果调用System.gc()满足您的需要,我建议使用spring scheduler每隔x个月运行一次定期任务

这很容易实现,有些注释

@EnableAsync
@EnableScheduling
@Scheduled(cron = "...")
这就是你所需要的。 有关详细信息,请参阅

编辑

调用System.gc()只给出启动垃圾收集的建议,何时启动还是由JVM决定

要了解系统是否空闲,可以使用spring度量。 有一些子类

org.springframework.boot.actuate.endpoint.PublicMetrics
例如TomcatPublicMetrics或SystemPublicMetrics,它们为您提供有关系统的信息。
您可以使用@Autowire将它们注入,并调用mertics()来获取单个值。根据这一点,您可以决定系统是否空闲,

这可能是的重复,调用“system.gc()”也不能保证在该点启动gc,请参阅我的问题不是该问题的重复。我了解GC的基本机制以及堆是如何返回给操作系统的。我也理解System.gc没有任何保证,尽管我还没有看到它忽略请求。我想讨论一下在系统空闲时如何最好地调用显式垃圾收集。抱歉,我似乎错过了你文章的真正要点“我的问题是:当JVM空闲时,确保将内存释放回操作系统的最佳方法是什么?”编辑后的问题以粗体显示;-)@拉塞尔:对不起,我错过了这个微妙之处。我重新开始了这个问题。嗯,是的。我只是在想那些台词。但我也认为,这样的解决方案也会在系统不空闲时触发不必要的垃圾收集。例如,在一个请求中触发一个完整的堆GC很可能会由于计划不佳的GC引起的很多长反应而毁掉了我的SLA。接受这个答案。感觉就像是一个黑客。我更喜欢一些外部解决方案,比如一个聪明的JVM标志或其他东西。