我们有一个简单的微服务设置,基于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是不可接受的,因为这会有很大的风险与有效请求冲突并破坏响应时间。
答案 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()来获取单个值。基于此,您可以决定,如果您的系统处于空闲状态,