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

时间:2016-07-01 14:56:10

标签: spring-boot garbage-collection jvm java-8 g1gc

我们有一个简单的微服务设置,基于Windows服务器上的Spring Boot和Java 8。

许多服务负载较低,因为它们可以作为各种外部合作伙伴的集成。所以他们很多时候都闲着。

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

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

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

一个想法是让服务监视器本身并在一段时间的闲置之后触发System.gc,但这可能是棘手和错误的。所以希望有更好的建议。

您可以通过运行此程序的X实例来重现。大约10个让我的Windows机器有8GB放弃了。

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]);
    }
  }
}

c:\> java -server -XX:+UseG1GC -Xms32m -Xmx2048m Load

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

1 个答案:

答案 0 :(得分:1)

如果调用System.gc()满足您的需求,我建议使用spring scheduler来为每个x sedonds运行一个周期性任务。

这很容易实现,有些注释

@EnableAsync
@EnableScheduling
@Scheduled(cron = "...")

就是你所需要的。 有关详细信息,请参阅spring scheduling

修改

调用System.gc()只给出了启动垃圾收集的建议,它仍由JVM决定何时进行垃圾收集。

要了解,如果您的系统处于空闲状态,您可以使用弹簧指标。

有一些子类
org.springframework.boot.actuate.endpoint.PublicMetrics

类似于TomcatPublicMetrics或SystemPublicMetrics,它们为您提供有关系统的信息。 您可以使用@Autowire注入它们并调用mertics()来获取单个值。基于此,您可以决定,如果您的系统处于空闲状态,