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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1582209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 16:28:10  来源:igfitidea点击:

Java garbage collector - When does it collect?

javagarbage-collection

提问by nalo

What is it that determines when the garbage collector actually collects? Does it happen after a certain time or after a certain amount of memory have been used up? Or are there other factors?

是什么决定了垃圾收集器实际收集的时间?它是在一段时间后还是在一定数量的内存用完后发生?还是有其他因素?

采纳答案by jalf

It runs when it determines that it is time to run. A common strategy in generational garbage collectors is to run the collector when an allocation of generation-0 memory fails. That is, every time you allocate a small block of memory (big blocks are typically placed directly into "older" generations), the system checks whether there's enough free space in the gen-0 heap, and if there isn't, it runs the GC to free up space for the allocation to succeed. Old data is then moved to the gen-1 heap, and when space runs out there, the GC runs a collection on that, upgrading the data which has been there longest to the gen-2 heap, and so on. So the GC doesn't just "run". It might run on the gen-0 heap only (and most collections will do just that), or it might check every generation if it really has to free up a lot of memory (which is only necessary fairly rarely).

它在确定是运行的时间时运行。分代垃圾收集器中的一个常见策略是在第 0 代内存分配失败时运行收集器。也就是说,每次分配一小块内存(大块通常直接放入“老”代)时,系统会检查 gen-0 堆中是否有足够的空闲空间,如果没有,则运行GC 来释放空间以便分配成功。然后将旧数据移动到第 1 代堆,当那里的空间用完时,GC 会对其进行收集,将在那里保存时间最长的数据升级到第 2 代堆,依此类推。所以 GC 不只是“运行”。它可能只在 gen-0 堆上运行(大多数集合都会这样做),

But this is far from the onlystrategy. A concurrent GC runs in the background, cleaning up while the program is running. Some GC's might run as part of every memory allocation. An incremental collector might do that, scanning a few objects at every memory allocation.

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

The entire point in a garbage collector is that it should just do its thing without requiring any input from the user. So in general, you can't, and shouldn't, predict when it'll run.

垃圾收集器的全部意义在于,它应该只做自己的事情,不需要用户的任何输入。所以总的来说,你不能也不应该预测它什么时候运行。

I believe Suns JVM gained a generational GC not too long ago (v1.6 maybe? I haven't coded Java for ages, so not sure on this, but I remember being surprised not too long ago, when one of the selling points for the new version was "a generational GC". Not least because .NET has had one since day 1.)

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

Other JVM's are of course free to pick whichever strategy they like.

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

EDIT:The above part about Java and generational GC is not true. See below for more details:

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

The 1.0 and 1.1 Virtual Machines used a mark-sweep collector, which could fragment the heap after a garbage collection. Starting with Java 1.2, the Virtual Machines switched to a generational collector, which has a much better defragmentation behavior (see Java theory and practice: Garbage collection and performance).

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

So Java actually has a generational GC for ages. What's new in Java 6 is the Garbage-First garbage collector (G1) that is available in Java 6u14. According to the article claiming the release in 1.6.0_14: It is not enabled by default. The parallel collector is still the default GC and is the most efficient GC for common household usage. G1 is meant to be an alternative for the concurrent collector. It is designed to be more predictable and enable fast allocation with memory regions design.

所以 Java 实际上有一个很长一段时间的分代 GC。Java 6 中的新增功能是 Java 6u14 中提供的垃圾优先垃圾收集器 (G1)。根据声称在 1.6.0_14 中发布的文章默认情况下未启用。并行收集器仍然是默认的 GC,并且是普通家庭使用的最高效的 GC。G1 旨在成为并发收集器的替代品。它被设计为更具可预测性,并通过内存区域设计实现快速分配。

回答by tschaible

It depends a lot on what garbage collector you're actually using, how its tuned, and a whole lot of inputs.

这在很大程度上取决于您实际使用的垃圾收集器、其调整方式以及大量输入。

For a run down of the HotSpot Garbage Collector (the common one that comes with Java) and how it's tuned, you can check out this link

要了解 HotSpot Garbage Collector(Java 附带的常见垃圾收集器)及其调整方式,您可以查看 此链接

回答by Xinus

  • It depends on way program JIT compiled.
  • From outside we cannot definitely tell when it will run.
  • It follows some algorithm which depends on that particular GC.
  • Java virtual machine runs on the client machine with some virtual memory in case of windows default is 4GB. It also depends on that free virtual memory at that particular time.
  • 这取决于程序 JIT 编译的方式。
  • 从外面我们不能确定它什么时候运行。
  • 它遵循一些取决于特定 GC 的算法。
  • Java 虚拟机运行在带有一些虚拟内存的客户端机器上,Windows 默认为 4GB。它还取决于那个特定时间的可用虚拟内存。

You can try this small program to check behavior of GC

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

possible output -- May be different in your case

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

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

Check this link http://www.devdaily.com/java/edu/pj/pj010008/

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

回答by rsp

The garbage collector runs when it needs resources and on a regular basis that you able to influence by telling when is a good time to spend CPU on collecting, using System.gc()

垃圾收集器在需要资源时运行,并定期运行,您可以通过使用System.gc()告诉何时是将 CPU 用于收集的好时机来影响

You can help the garbage collector by nulling references explicitly, for instance by giving your objects init()methods that allocate resources and cleanup()methods that explicitly clean up those resources and nulling their references. By nulling references yourself you prevent tye garbage collector from having to find clusters of obects that have to more paths to a root.

您可以通过显式清空引用来帮助垃圾收集器,例如通过为您的对象提供init()分配资源的cleanup()方法和显式清理这些资源并清空它们的引用的方法。通过自己清空引用,您可以防止垃圾收集器不得不查找必须有更多路径到根的对象簇。

回答by Thorbj?rn Ravn Andersen

This completely depends on the actual JVM and what it chooses to do, and is basically out of your hands as a programmer. Greybearded die-hard experts maywant to tell the JVM they know better, but for mere mortals this should be considered black magic better left alone.

这完全取决于实际的 JVM 以及它选择做什么,并且基本上是程序员无法掌控的。灰胡子顽固的专家可能想告诉 JVM 他们更了解他们,但对于凡人来说,这应该被认为是黑魔法,最好不要管它。

What should concern you is if it can keep up with the rate that your programs creates and discards objects. If not your wholeprogram is halted while global cleaning up occurs. That turns out to very bad response times, but happens rarely for modern JVM's on modern computers.

您应该关心的是它是否能够跟上您的程序创建和丢弃对象的速度。如果不是,您的整个程序将在全局清理发生时停止。事实证明,响应时间非常短,但对于现代计算机上的现代 JVM 而言,这种情况很少发生。

If you are curious about what happens in your program and when, then investigate the "jvisualvm" tool in the recent versions of the Java 6 JDK. It is really great for peeking inside.

如果您对程序中发生的事情以及何时发生感到好奇,那么请研究 Java 6 JDK 最新版本中的“jvisualvm”工具。真的很适合偷看里面。

回答by Nisal Edu

When JVM don't have necessary memory space to run, garbage collector will run and delete unnecessary objects and allocate memory for JVM.

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

Unnecessary objects are the objects which have no reference (address) for it.

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

There are mainly 4 points for objects to eligible for garbage collector.

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

  1. Null Referencing

    Garbage collector can delete an object when the reference variable of the object is assigned null as it's value

        A a = new A();
        a = null;
    
  2. Re-assigning

    When another object is assigned to the reference variable of an object the older referenced object can be deleted by garbage collector.

      A a = new A(100);
      a =new A(200);
    
  3. Local Scope

    If an object is created inside a block that object is eligible for garbage collector out side that block.

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

    An object can refer another object but there must be at least one reference (address) variable for these objects in stack, otherwise all those objects are eligible for garbage collector.

          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  
    
  1. 空引用

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

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

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

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

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

      if(condition){
    
         A a = new A();
    
      }
    
  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