我想问你如何(或IF)可以减少Spring框架的RAM占用空间。
我创建了一个简单的helloworld应用程序来演示这个问题。只有两个类和context.xml文件:
Main
- 使用main方法的类Test
- 用于模拟某些“工作”的类(无限循环中的printig Hello) context.xml
仅包含此内容:
<context:component-scan base-package="mypackage" />
测试类仅包含名为init
的metod,在构造之后调用:
@Component
public class Test{
@PostConstruct
public void init() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Hello " + Thread.currentThread().getName());
Thread.sleep(500);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
});
t.start();
}
}
我准备了两个场景,在两个场景中main
方法只包含一行。
在第一个场景中,main方法执行此操作:(new Test()).init();
应用程序没有Spring工作,只消耗aprox。 8MB RAM。
在第二个场景中,main方法包含以下内容:new ClassPathXmlApplicationContext(new String[]{"spring/context.xml"});
因此,应用程序通过Spring容器初始化并消耗aprox。 45MB RAM!
有什么方法可以减少(在最好的情况下完全摆脱)这个额外的内存?到目前为止,我无法找到任何合适的解决方案。
我不介意启动时是否有额外的内存消耗 - 这很好,但在那之后,我需要我们的应用来减少它。
(这个问题背后的故事有点复杂,但这对我来说现在是核心问题。)
谢谢
答案 0 :(得分:30)
首先,您可能已经了解了一些事情,但了解情况很重要:程序使用的大部分内存是 JVM堆。程序开始执行时,堆具有初始大小。有时,JVM会向操作系统请求更多内存并增加堆的大小。 JVM还将执行垃圾收集,从而释放堆中的空间。
当使用的堆大小减小时,内存不一定由JVM释放。 oracle JVM不愿意这样做。例如,如果您的程序在启动时使用500 MB的ram,那么在垃圾收集仅在其大部分执行时使用100 MB时,您不能假设额外的400 MB将被返回给您的操作系统。
此外,Windows任务管理器(我假设unix的ps
)等工具将显示分配给JVM的所有内存的大小,无论是否实际使用此内存即可。像jvisualvm这样的工具可以让你准确地看到java程序中内存的使用方式,特别是你实际使用的堆数量与分配的数量。
考虑到这一点,我在以下场景中测试了您的程序。请注意,这取决于许多因素,包括您使用的JVM,版本以及可能的操作系统。
对于每种情况,我都会报告分配的堆大小和使用的堆大小。以下是我的结果:
这些结果是相同的,所以根据你的问题,我假设你已经拥有了与我不同的环境。
使用GC可以减少堆使用量,但我们仍然拥有相同的已分配内存
这是最重要的结果:分配了更多内存,因为Spring在启动期间可能需要更多内存。
<强>结论:强>
-XX:MaxHeapFreeRatio=70
之类的jvm选项可能是一个开始(更多http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#PerformanceTuning)