Java垃圾收集器 - 什么时候收集?

nal*_*alo 46 java garbage-collection

什么是垃圾收集器实际收集的时间?它会在一段时间后或在一定量的内存耗尽后发生吗?还是有其他因素吗?

jal*_*alf 28

它在确定是时候运行时运行.分代代垃圾收集器的一个常见策略是在分配0代内存失败时运行收集器.也就是说,每次分配一小块内存(大块通常直接放入"旧"代)时,系统会检查gen-0堆中是否有足够的可用空间,如果没有,则运行GC为释放空间以便分配成功.然后旧数据被移动到gen-1堆,当空间用完时,GC运行一个集合,升级第二代堆中最长的数据,依此类推.所以GC不只是"运行".它可能只在gen-0堆上运行(并且大多数集合都会这样做),或者它可能会检查每一代是否真的需要释放大量内存(这是非常必要的).

但这远非唯一的策略.并发GC在后台运行,在程序运行时进行清理.某些GC可能作为每个内存分配的一部分运行.增量收集器可能会这样做,在每次内存分配时扫描一些对象.

垃圾收集器中的全部内容是它应该只需要做其事情而无需用户的任何输入.所以一般来说,你不能也不应该预测它什么时候运行.

我相信太阳JVM不久前获得了一代GC(也许是v1.6?我已经很久没有编写Java了,所以不确定这个,但我记得不久前很惊讶,当时的卖点之一新版本是"世代GC".尤其是因为.NET从第1天起就有了一个.)

其他JVM当然可以自由选择他们喜欢的策略.

编辑:上面关于Java和世代GC的部分是不正确的.请参阅下面的更多细节:

1.0和1.1虚拟机使用了标记扫描收集器,它可以在垃圾收集后对堆进行分段.从Java 1.2开始,虚拟机切换到分代收集器,它具有更好的碎片整理行为(参见Java理论和实践:垃圾收集和性能).

所以Java实际上已经有了几代人的GC.Java 6中的新功能是Java 6u14中提供的Garbage-First垃圾收集器(G1).根据声称1.6.0_14版本的文章:默认情况下不启用它.并行收集器仍然是默认的GC,是普通家庭使用的最有效的GC.G1意味着是并发收集器的替代品.它旨在更加可预测,并通过内存区域设计实现快速分配.


Xin*_*nus 7

  • 这取决于程序JIT编译的方式.
  • 从外面我们无法确定何时会运行.
  • 它遵循一些依赖于特定GC的算法.
  • 如果Windows默认为4GB,则Java虚拟机在客户端计算机上运行一些虚拟内存.它还取决于该特定时间的免费虚拟内存.

您可以尝试这个小程序来检查GC的行为

public class GCTest {

   final int NELEMS = 50000;

   void eatMemory() {

      int[] intArray = new int[NELEMS];

      for (int i=0; i<NELEMS; i++) {
        intArray[i] = i;
      }

   }

   public static void main (String[] args) {

      GCTest gct = new GCTest();

      // Step 1: get a Runtime object
      Runtime r = Runtime.getRuntime();

      // Step 2: determine the current amount of free memory
      long freeMem = r.freeMemory();
      System.out.println("free memory before creating array: " + freeMem);

      // Step 3: consume some memory
      gct.eatMemory();

      // Step 4: determine amount of memory left after consumption
      freeMem = r.freeMemory();
      System.out.println("free memory after creating array:  " + freeMem);

      // Step 5: run the garbage collector, then check freeMemory
      r.gc();
      freeMem = r.freeMemory();
      System.out.println("free memory after running gc():    " + freeMem);
   }
}
Run Code Online (Sandbox Code Playgroud)

可能的输出 - 在您的情况下可能会有所不同

free memory before creating array: 4054912
free memory after creating array:  3852496
free memory after running gc():    4064184
Run Code Online (Sandbox Code Playgroud)

查看此链接http://www.devdaily.com/java/edu/pj/pj010008/


Nis*_*Edu 7

当 JVM 没有运行所需的内存空间时,垃圾收集器将运行并删除不需要的对象并为 JVM 分配内存。

不必要的对象是没有引用(地址)的对象。

对象符合垃圾收集器的条件主要有 4 点。

  1. 空引用

    当对象的引用变量被赋值为 null 时,垃圾收集器可以删除该对象

        A a = new A();
        a = null;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 重新分配

    当另一个对象被分配给一个对象的引用变量时,垃圾收集器可以删除旧的引用对象。

      A a = new A(100);
      a =new A(200);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 本地范围

    如果对象是在块内创建的,则该对象有资格在该块外进行垃圾收集器。

      if(condition){
    
         A a = new A();
    
      }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 隔离

    一个对象可以引用另一个对象,但堆栈中必须至少有这些对象的一个​​引用(地址)变量,否则所有这些对象都有资格进行垃圾收集器。

          class A{
                A r;
                A(int i){
                 //something   
               }
          } 
    
          A a1 = new A(100);
          a1.r = new A(101);
          a1.r.r = new A(102);
          a1.r.r.r = a1;
    
          a1  = null //all ojects are eligible to garbage collector  
    
    Run Code Online (Sandbox Code Playgroud)


tsc*_*ble 5

这在很大程度上取决于你实际使用的垃圾收集器,它的调整方式以及大量的输入.

对于HotSpot垃圾收集器(Java附带的常见垃圾收集器)的运行及其调整方式,您可以查看 此链接