这是我的主要应用程序问题的示例代码。当我生成数据时,它继续占用RAM(顺便说一句)。但是当我停止该进程时,它仍然保留在RAM中(我可以在任务管理器中看到它)。我尝试使用System.gc()
,但是也没有用。由于占用更多内存,程序有时会卡住。希望有人能帮助我。
public static ArrayList<String> my = new ArrayList<>();
public static int val = 0;
// Code for Start Button
try {
new Thread(new Runnable() {
@Override
public void run() {
String ss = "";
for (int i = 0; i < 10000; i++) {
ss += "ABC";
}
while (true) {
if (val == 0) {
for (int i = 0; i < 30; i++) {
my.add(ss + new SimpleDateFormat("yyyyMMddHHmmssSSS"));
}
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
}
} else {
Thread.yield();
break;
}
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
// Code for Stop Button
val = 1;
my.clear();
my = null;
System.gc();
Runtime.getRuntime().freeMemory();
答案 0 :(得分:2)
垃圾收集取决于各种因素,例如您使用的是哪个收集器,计算机的物理内存以及您使用的JVM版本。由于您在这里没有太多提及它们,因此很难预测这可能是造成这种情况的原因。我认为您正在使用Java 8,因为它是当今最受欢迎的版本。
自Java 8开始,JVM内存模型发生了变化。也就是说,现在没有Permanent Generation
空间。这是String Pool
所在的空间(我要使用String
,因此您在循环中使用String
串联)。请参阅此Java (JVM) Memory Model – Memory Management in Java文档。自您声明类/静态引用以来,Permanent Generation
就一直存在。
从Java 8开始,取代了Permanent Generation
,有了一个名为Metaspace
的新内存位置,该位置位于JVM之外的主内存中。
此外,当像这样串联String
对象时,它不会修改现有对象,因为String
是不可变的类型。而是使用新值创建新的String
对象,并将它们放入Metaspace
中。这可能是您看到内存使用量增加的原因。
即使Metaspace
位于主内存/物理内存中并且可以动态扩展,但是仍然存在物理内存限制。这就是为什么我将早期机器的物理内存作为依赖性因素的原因。
当我们进行垃圾收集时,您没有提到任何GC配置。因此,我假设您正在使用并行GC ,它是Java 8的默认收集器(您可以从上面提供的同一链接中找到有关GC的更多信息)。我猜想Parallel GC
的性能足以胜任此任务。因此,在没有任何JVM标志的情况下调用System.gc()
就足够了。
但是,正如您提到的System.gc()
不会清理内存可能会发生,因此您正在使用单独的线程来连接这些字符串。
通常,使用String文字(String s = "abc"
)创建的String不会成为垃圾回收对象。这是因为在使用文字的每种方法的代码中都有对String
对象的隐式引用(请检查答案When will a string be garbage collected in java)。因此,您必须通过结束函数的执行来释放那些隐式引用。
由于您使用的是新的Thread
来进行此串联,因此我找不到任何中断线程的地方,并且正在调用Thread.yield()
(Thread.yield)要通知线程调度程序抓住该特定线程的CPU使用率并标记该线程愿意尽快进行调度,请非常清楚此Thread
对象仍然存在,并引用那些String对象,使它们符合垃圾标准。这可能是System.gc()
调用无法正常工作的原因。
作为解决方案,请尝试interrupt
而不是yield
线程。
更新1:
在Java 7之前,String Pool
位于PermGen
中,不能进行垃圾收集。 PermGen
的大小固定,无法在运行时扩展。如果PermGen
没有足够的空间,则会出现java.lang.OutOfMemoryError: PermGen
错误。作为临时补救措施,我们可以使用PermGen
标志来增加-XX:MaxPermSize=512m
的大小。
但是请记住,这仅适用于Java 8之前的JVM和Java 7,这在增加String Pool
大小可用性方面没有任何区别,因此从Java 7起,String Pool
到Heap
空间。