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
均指同一对象clear
将不实际清除从main
传递的数组mas
此时GC没有可用的内容:
- 您仍然有一个引用(
)引用ArrayList,该ArrayList包含最初由list
引用的对象(其中包含“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