Tha*_*lur 23 java garbage-collection nested-class
我只是遇到了一个奇怪的效果,在跟踪它时,我注意到收集内部和静态嵌套类似乎有很大的性能差异.考虑以下代码片段:
public class Test {
private class Pointer {
long data;
Pointer next;
}
private Pointer first;
public static void main(String[] args) {
Test t = null;
for (int i = 0; i < 500; i++) {
t = new Test();
for (int j = 0; j < 1000000; j++) {
Pointer p = t.new Pointer();
p.data = i*j;
p.next = t.first;
t.first = p;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么代码所做的就是使用内部类创建一个链表.该过程重复500次(用于测试目的),丢弃上次运行中使用的对象(受GC影响).
在内存限制严格(例如100 MB)下运行时,此代码在我的计算机上执行大约需要20分钟.现在,通过简单地用静态嵌套类替换内部类,我可以将运行时减少到不到6分钟.以下是更改:
private static class Pointer {
Run Code Online (Sandbox Code Playgroud)
和
Pointer p = new Pointer();
Run Code Online (Sandbox Code Playgroud)
现在我从这个小实验中得出的结论是,使用内部类会使GC更难以确定是否可以收集对象,这使得静态嵌套类在这种情况下的速度提高了3倍以上.
我的问题是这个结论是否正确; 如果是的话是什么原因,如果没有为什么内部课程这么慢?
dis*_*tor 16
我想这可能是由于两个因素造成的.你已经触及过的第一个.第二种是使用非静态内部类导致更多的内存使用.你为什么问?因为非静态内部类也可以访问其包含类的数据成员和方法,这意味着您正在分配一个基本上扩展超类的Pointer实例.对于非静态内部类,您不会扩展包含类.这是我正在谈论的一个例子
Test.java(非静态内部类)
public class Test {
private Pointer first;
private class Pointer {
public Pointer next;
public Pointer() {
next = null;
}
}
public static void main(String[] args) {
Test test = new Test();
Pointer[] p = new Pointer[1000];
for ( int i = 0; i < p.length; ++i ) {
p[i] = test.new Pointer();
}
while (true) {
try {Thread.sleep(100);}
catch(Throwable t) {}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Test2.java(静态内部类)
public class Test2 {
private Pointer first;
private static class Pointer {
public Pointer next;
public Pointer() {
next = null;
}
}
public static void main(String[] args) {
Test test = new Test();
Pointer[] p = new Pointer[1000];
for ( int i = 0; i < p.length; ++i ) {
p[i] = new Pointer();
}
while (true) {
try {Thread.sleep(100);}
catch(Throwable t) {}
}
}
}
Run Code Online (Sandbox Code Playgroud)
当两者都运行时,您可以看到非静态占用的堆空间比静态占用的多.具体来说,非静态版本使用2,279,624 B,静态版本使用10,485,760 1,800,000 B.
因此,它归结为非静态内部类使用更多内存,因为它包含对包含类的引用(至少).静态内部类不包含此引用,因此永远不会为其分配内存.通过将堆大小设置得如此之低,您实际上正在颠倒堆,从而导致3倍的性能差异.
当您接近最大堆大小(-Xmx)时,垃圾收集的成本非常非线性地增加,其中JVM最终放弃并且抛出OutOfMemoryError的接近无限的人为限制.在这种特殊情况下,您会看到该曲线的陡峭部分位于内部类之间是静态的还是非静态的.除了使用更多内存和拥有更多链接之外,非静态内部类并不是真正的原因.我已经看到许多其他的代码更改"导致"GC捶打,他们恰好是将其推到边缘的不幸的闷棍,并且堆限制应该简单地设置得更高.这种非线性行为通常不应被视为代码的问题 - 它是JVM的固有特性.
当然,另一方面,膨胀是膨胀的.在目前的情况下,一个好习惯是使内部类"默认"为静态,除非访问外部实例是有用的.
归档时间: |
|
查看次数: |
5737 次 |
最近记录: |