Lau*_*ves 28 java garbage-collection anonymous-class
我正在处理一些代码,其中一个对象"foo"正在创建另一个对象"bar",并将其传递给它Callable.在此foo之后将返回bar,然后我希望foo变得无法访问(即:可用于垃圾收集).
我最初的想法是Callable匿名创建.例如:
class Foo {
...
public Bar createBar() {
final int arg1 = ...
final int arg2 = ...
final int arg3 = ...
return new Callable<Baz>() {
@Override
public Baz call() {
return new Baz(arg1, arg2, arg3);
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这可能实际上并不按预期工作,因为内部类通常会保持对其封闭对象的引用.我不希望在这里引用封闭类,因为我希望在Callable仍然可以访问时收集封闭对象.
另一方面,检测到实际上从未引用封闭实例应该是非常简单的,因此Java编译器可能足够聪明,在这种情况下不包括引用.
那么......一个匿名内部类的实例是否会持有对其封闭实例的引用,即使它实际上从未使用封闭的实例引用?
Lau*_*ves 30
是的,匿名内部类的实例持有对其封闭实例的引用,即使这些引用从未实际使用过.这段代码:
public class Outer {
public Runnable getRunnable() {
return new Runnable() {
public void run() {
System.out.println("hello");
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
编译时javac生成两个类文件,Outer.class和
Outer$1.class.拆解后者,匿名内部类,javap -c收益率:
Compiled from "Outer.java"
class Outer$1 extends java.lang.Object implements java.lang.Runnable{
final Outer this$0;
Outer$1(Outer);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LOuter;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return
public void run();
Code:
0: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4; //String hello
5: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
Run Code Online (Sandbox Code Playgroud)
该putfield行显示对封闭实例的引用由构造函数存储在字段this$0(类型Outer)中,即使此字段永远不会再次使用.
如果您尝试使用匿名内部类创建小的可能长寿命的对象,这将是不幸的,因为它们将保留在(可能很大的)封闭实例上.解决方法是使用静态类(或顶级类)的实例.不幸的是,这更加冗长.
小智 5
通过在类中引入静态方法,您可以轻松地将嵌套的匿名类转换为"静态"匿名类.
import java.util.ArrayList;
public class TestGC {
public char[] mem = new char[5000000];
public String str = "toto";
public interface Node {
public void print();
}
public Node createNestedNode() {
final String str = this.str;
return new Node() {
public void print() {
System.out.println(str);
}
};
}
public static Node createStaticNode(TestGC test) {
final String str = test.str;
return new Node() {
public void print() {
System.out.println(str);
}
};
}
public Node createStaticNode() {
return createStaticNode(this);
}
public static void main(String... args) throws InterruptedException {
ArrayList<Node> nodes = new ArrayList<Node>();
for (int i=0; i<10; i++) {
// Try once with createNestedNode(), then createStaticNode()
nodes.add(new TestGC().createStaticNode());
System.gc();
//Thread.sleep(200);
System.out.printf("Total mem: %d Free mem: %d\n", Runtime.getRuntime().totalMemory(), Runtime.getRuntime().freeMemory());
}
for (Node node : nodes)
node.print();
nodes = null;
System.gc();
//Thread.sleep(200);
System.out.printf("Total mem: %d Free mem: %d\n", Runtime.getRuntime().totalMemory(), Runtime.getRuntime().freeMemory());
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7617 次 |
| 最近记录: |