Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中垃圾收集器的工作_Java_Garbage Collection - Fatal编程技术网

Java中垃圾收集器的工作

Java中垃圾收集器的工作,java,garbage-collection,Java,Garbage Collection,在调用System.gc()时,哪些对象可用于垃圾收集?为什么 public class GCTest { static class A { private String myName; public A(String myName) { this.myName = myName; } } public static void main(String[] args) { A a1 =

在调用
System.gc()
时,哪些对象可用于垃圾收集?为什么

public class GCTest {
    static class A {
        private String myName;
        public A(String myName) {
            this.myName = myName;
        }
    }

    public static void main(String[] args) {
        A a1 = new A("a1");
        A a2 = new A("a2");
        ArrayList list = new ArrayList();
        list.add(a1);
        A[] mas = new A[2];
        mas[0] = a2;
        a2 = a1;
        clear(mas);
        a1 = null;
        a2 = null;
        System.gc();
        // some code
        ...
    }

    private static void clear(A[] mas) {
        mas = null;
    }
} 
如果
object==null
它是否会变成垃圾


我认为
a1
a2
mas
在调用
System.gc()
时可用于垃圾收集,因为它的状态为null。或者我错了?

没有人有资格获得GC:

  • ArrayList
    仍然可以访问,并且引用了
    a1
  • a2
    a1
    均指同一对象
  • 最重要的是,由于Java是按值传递的,因此方法
    clear
    实际清除从
    main
    传递的数组
    mas
  • 下面是调用GC时内存中对象的图示:


    此时GC没有可用的内容:

    • 您仍然有一个引用(
      list
      )引用ArrayList,该ArrayList包含最初由
      a1
      引用的对象(其中包含“a1”字符串)
    • 您仍然有一个引用(
      mas
      )引用数组,该数组包含最初由
      a2
      引用的对象(其中包含“a2”字符串)
    请注意,您的方法

    private static void clear(A[] mas) {
        mas = null;
    }
    
    什么也不做

    Java是按值传递的。因此,当调用此方法时,将创建数组引用的副本并将其传递给该方法。然后,该方法将null赋值给原始引用的副本,使原始引用保持不变


    请参阅以获取更多解释。

    首先,您的程序变量永远不会“用于垃圾收集”。GC只收集对象,程序变量是对对象的引用,而不是对象本身。(引用Java变量的常用术语混淆了这一点。)

    其次,
    a1
    a2
    mas
    引用的对象都不会被GC'ed。尽管
    a1
    a2
    已设置为
    null
    。这是因为对这些对象的引用仍然可以通过
    list
    mas
    访问。为什么即使在调用
    clear()
    之后,
    a2
    引用的对象仍然可以通过
    mas
    访问?因为您无法通过将变量传递给方法
    clear()
    来更改
    main()
    中变量
    mas
    的值。您在该方法中所做的只是更改形式参数(也称为
    mas
    ),它是与
    main()
    中的局部变量不同的一个变量。Java严格按值传递。然而,当涉及到对象时,总是传递的是引用


    一般来说,规则是,只有当对象无法从任何程序变量直接或间接访问时,才对对象进行GC。

    调用
    System.GC()
    时,由new A(“a1”)、new A(“a2”)和mas创建的对象不会被垃圾收集

    线程直接或间接引用的任何对象都不可用于gc。线程正在运行此方法,因此将保留局部变量

    newa(“a1”)
    (我们称之为
    a1
    )创建的对象为例


    在System.gc()运行时,
    list
    在其内部结构中引用对象
    A1
    ,因此即使未在
    A1
    中引用,也不会对其进行垃圾收集。唯一指定的关于对象可达性的规则如下():

    可访问对象是可以从任何活动线程在任何可能的连续计算中访问的任何对象


    通过检查您的代码,很明显,在任何潜在的连续计算中都无法访问任何对象。
    main
    完成后,将不存在对其中任何一个的引用;此外,
    System.gc()
    是程序中的最后一条语句,该语句的计算将不会访问这些对象或任何其他对象(它在Java级别上没有任何语义)。因此,无论垃圾收集的实际实现是否意识到这一点,所有对象实际上都是不可访问的。

    这实际上不是最后一条语句,因为该方法以
    //some code…
    结尾,这很可能意味着调用gc()之后会有更多的代码。即使没有代码遵循,GC是否有足够的信息知道没有代码遵循,变量永远不会被再次使用。我不是低级GC和JVM专家,但我认为不是。如果你坚持规范,我认为你的答案事实上是正确的,但有点……吹毛求疵,因为在实践中,好吧,没有什么是正确的我认为这是一个吹毛求疵的问题:它来自一个作业/面试,它显然要求直接从规范中得到权威性的答案。因此,这主要取决于“某些代码”是什么”“是的。顺便说一句,当人们用松散的推理来决定某个OOME在某一点上是否可能时,挑剔就少多了。例如,即使是超出范围的变量也可以在实践中有效地防止无法访问的对象被GC化(这是我当前答案的另一面)+1用于提醒我们规格。但是,鉴于OP还不明白引用是如何传递给方法的,因此他可能正在面试一个入门级职位,如果面试官期望得到这样一个准确的答案,我会感到非常惊讶:-)是的,这个问题间接地探讨了对其他语言语义的理解;可以通过询问某个语句是否会抛出NPE来更直接地研究这些问题。这里:
    void x(){{long[]long1=new long[Integer.MAX_VALUE];}System.gc();long[]long2=new long[Integer.MAX_VALUE];}
    注意嵌套的
    {}
    块<代码>长1