垃圾收集器不会立即收集完成的线程

BAE*_*RUS 20 java multithreading garbage-collection memory-management

简而言之:我有一个完成运行的线程,但没有收集垃圾.

长:请参阅以下示例代码:

public void saveSomething() {
    Thread thread = new Thread(new Runnable() {

         @Override
         public void run() {
             // heavy memory access (~400 MB), finishes after ~10sec
         }
    });
    thread.start();
}
Run Code Online (Sandbox Code Playgroud)

好的,所以这个线程在一段时间后开始并完成.在此期间使用了大量内存,这没关系.但我的问题是:

线程完成后,内存未设置为空闲

我不知道如何确保这一点.完成的线程,不再使用,应该收到垃圾收集,据我所知; 但这似乎不会发生在这里:(

从jvisualVM看这个截图:

在此输入图像描述

1:我通过调用触发线程启动 saveSomething()

2:线程很久以前就已经完成了(我通过调试看到了它),我在jvisualvm中按下了"Perform GC"

正如你所看到的,在我强制GC之后,一切都按照我想要的方式工作.但这必须自动发生.我怎么能这样做,我做错了什么?

如果您需要更多信息,请询问.注意:似乎在一天(希望更短)后,内存恢复正常,GC可能只是"慢"或者不是经常定时?

Gho*_*ica 34

难道你问的是错误的问题吗?我的意思是:垃圾收集不会"立即"出现问题吗?

我很确定 - 当你启动另一个需要大量内存的线程时,GC将自行启动.

如果"延迟"对您来说实际上是一个问题,您可以考虑进行"非常深入的研究",以了解GC实际上如何适用于您的JVM版本; 然后开始使用现有的许多命令行选项来根据您的需要微调GC行为.

但是,如果释放内存(对其他Java对象)的"延迟"不是问题; 然后不要开始修复它.


Sil*_*ICE 22

线程完成后不会发生垃圾收集.垃圾收集会在发生时发生.当您通过visualvm强制进行垃圾收集时,正确收集线程及其资源意味着一切正常.如果你等待足够长的时间或做更多消耗堆的事情,那么最终你的线程将被GCed.

编辑 唯一需要注意的是,即使没有引用,正在运行的线程也不会被垃圾回收.


Pat*_*han 18

我同意以前的答案.该程序演示了"问题"并非特定于线程创建的事实.通常,gc在需要时或在特别要求时完成.

public class Test {

  public static long memInUse(){
    Runtime r = Runtime.getRuntime();
    return r.totalMemory()-r.freeMemory();
  }

  public static void main(String[] args){
    System.out.println("Initial memory: "+memInUse());
    long[] bigArray = new long[1000000];
    System.out.println("Memory after array allocation: "+memInUse());
    long endTime = System.currentTimeMillis()+10000;
    while(System.currentTimeMillis() < endTime){
      System.out.println("While array exists: "+memInUse());
      try{
        Thread.sleep(1000);
      }catch(InterruptedException e){
        // Deliberately ignore the exception.
      }
    }
    bigArray = null;
    System.out.println("After null assignment: "+memInUse());
    endTime = System.currentTimeMillis()+10000;
    while(System.currentTimeMillis() < endTime){
      System.out.println("While array reference null: "+memInUse());
      try{
        Thread.sleep(1000);
      }catch(InterruptedException e){
        // Deliberately ignore the exception.
      }
    }
    System.gc();
    System.out.println("After gc: "+memInUse());
  }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Initial memory: 2684536
Memory after array allocation: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
While array exists: 10684552
After null assignment: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
While array reference null: 10684552
After gc: 1622584
Run Code Online (Sandbox Code Playgroud)

  • 我特别喜欢这样一个事实,即最后一行显示的内存少于'初始内存'. (2认同)

Phi*_*son 8

完全有可能JVM在线程完成后根本不需要执行GC,因为它有足够的空闲堆.

只有在需要释放内存时才会执行GC.

就个人而言,我不担心.只要你知道当GC发生时内存将被清除,那就没关系了.

如果你真的想要强制它,你必须在线程完成之后做一个显式的System.GC,或者作为run()方法的最后一行(假设没有对大数据的进一步引用)在那个阶段).