Java垃圾收集器 – 它什么时候收集?

什么是什么决定垃圾收集器实际收集的时间? 这是否发生在一定的时间或一定量的内存已经用完之后? 还是还有其他因素?

它在确定是时候运行时运行。 分代垃圾收集器的一个常见策略是在分配0代存储器失败时运行收集器。 也就是说,每次你分配一个小块的内存(大的块通常直接放在“老”的世代),系统检查在gen-0堆中是否有足够的空闲空间,如果没有,就运行GC为释放分配空间腾出空间。 旧数据然后移动到第一代堆,当空间耗尽时,GC运行一个集合,将最长的数据升级到第二代堆,依此类推。 所以GC不只是“运行”。 它可能只在gen-0堆上运行(并且大多数集合都会这样做),或者它可能检查每一代是否真的需要释放大量内存(这只是相当less的)。

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

垃圾收集器中的全部要点是它只需要做它的事情,而不需要用户的任何input。 所以一般来说,你不能,也不应该预测什么时候会跑。

我相信太阳JVM在不久之前获得了世代GC(V1.6也许?我没有编码Java的年龄,所以不能确定这一点,但我记得很久以前感到惊讶,当时的一个卖点新版本是“一代GC”,不仅仅是因为.NET自1日起就有了1)

其他JVM当然可以自由select他们喜欢的策略。

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

1.0和1.1虚拟机使用标记清除收集器,这可能在垃圾收集之后碎片化堆。 从Java 1.2开始,虚拟机切换到一个世代收集器,它具有更好的碎片整理行为(请参阅Java理论和实践:垃圾收集和性能 )。

所以Java实际上有一个世代GC。 Java 6中的新增function是Java 6u14中的垃圾优先垃圾回收器(G1)。 根据1.6.0_14中声称发布的文章 : 默认情况下不启用。 并行收集器仍然是默认的GC,是普通家庭使用的最有效的GC。 G1是为了并发收集器的替代品。 它的devise更具可预测性,并且能够通过内存区域devise进行快速分配。

  • 这取决于程序JIT编译的方式。
  • 从外面我们不能确定什么时候运行。
  • 它遵循一些依赖于特定GC的algorithm。
  • Java虚拟机在客户端机器上运行一些虚拟内存,以防Windows默认为4GB。 这也取决于那个特定时间的空闲虚拟内存。

你可以试试这个小程序来检查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); } } 

可能的输出 – 在你的情况可能会有所不同

 free memory before creating array: 4054912 free memory after creating array: 3852496 free memory after running gc(): 4064184 

检查这个链接http://www.devdaily.com/java/edu/pj/pj010008/

它很大程度上取决于你实际使用的垃圾回收器,如何调整垃圾回收器以及大量的input。

对于HotSpot垃圾收集器(与Java一起使用的常见垃圾收集器)以及如何进行调整,您可以查看此链接

这完全取决于实际的JVM以及它select做什么,作为程序员基本上不在你的手中。 Greybearded铁杆专家可能想要告诉JVM他们知道更好,但对于凡人来说,这应该被视为更好的黑魔法。

你应该关心的是如果它能跟上你的程序创build和抛弃对象的速度。 如果不是,当全局清理发生时,您的整个程序都会中止。 现在的结果是非常糟糕的响应时间,但在现代计算机上很less发生现代JVM。

如果您对程序中以及何时发生的事情感到好奇,那么请调查最新版本的Java 6 JDK中的“jvisualvm”工具。 里面偷看真是太棒了。

垃圾回收器在需要资源的时候运行,并且通过告诉CPU什么时候收集CPU,通过使用System.gc()

你可以通过显式地cleanup()引用来帮助垃圾收集器,例如通过给你的对象分配资源的init()方法和明确清理这些资源并cleanup()引用的cleanup()方法。 通过自己使引用无效,可以防止tye垃圾收集器不得不查找必须有更多path到根的obects集群。

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

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

对象符合垃圾回收器主要有4点。

  1. 空引用

    当对象的引用variables被赋值为空时,垃圾收集器可以删除对象

      A a = new A(); a = null; 
  2. 重新分配

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

      A a = new A(100); a =new A(200); 
  3. 本地范围

    如果一个对象是在一个块内创build的,那么这个对象有资格在垃圾收集器的外面那个块。

      if(condition){ A a = new A(); } 
  4. 隔离

    一个对象可以引用另一个对象,但是对于堆栈中的这些对象必须至less有一个引用(地址)variables,否则所有这些对象都符合垃圾回收器的条件。

      class A{ A r; A(int i){ //something } } A a1 = new A(100); a1.r = new A(101); a1.rr = new A(102); a1.rrr = a1; a1 = null //all ojects are eligible to garbage collector