内部类与静态嵌套类的GC性能相比 [英] GC performance hit for inner class vs. static nested class

查看:92
本文介绍了内部类与静态嵌套类的GC性能相比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚遇到了一个奇怪的效果,并且在追踪它的同时,我注意到收集内部和静态嵌套类似乎存在显着的性能差异。考虑这段代码片段:

  public class Test {
private class Pointer {
long data;
下一个指针;
}
第一个私人指针;

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 ++){
指针p = t.new指针();
p.data = i * j;
p.next = t.first;
t.first = p;
}
}
}
}

代码所做的是使用内部类创建链接列表。该过程重复500次(用于测试目的),丢弃最后一次运行中使用的对象(其受到GC的影响)。



在内存限制严格的情况下运行(比如100 MB),这段代码大约需要20分钟才能在我的机器上执行。现在,只需用一个静态嵌套类替换内部类,就可以将运行时间缩短到不到6分钟。这里有一些变化:

  private static class Pointer {

 指针p =新的指针(); 

现在我从这个小实验中得出的结论是,使用内部类使得GC更加困难找出是否可以收集对象,在这种情况下使静态嵌套类速度提高3倍以上。



我的问题是这个结论是否正确;如果是的话是什么原因,如果没有,为什么内部类在这里慢得多?

解决方案

我想可能是因为到2个因素。你已经谈到的第一个。第二个是使用非静态的内部类,导致更多的内存使用。你为什么问?因为非静态内部类也可以访问它们包含的类数据成员和方法,这意味着你正在分配一个基本上扩展超类的指针实例。在非静态内部类的情况下,你不扩展包含类。这里是我正在谈论的一个例子



Test.java(非静态内部类)

  public class Test {
第一个私有指针;

私人班级指针{
下一个公共指针;
public Pointer(){
next = null;



public static void main(String [] args){
Test test = new Test();
指针[] p =新指针[1000];
for(int i = 0; i< p.length; ++ i){
p [i] = test.new指针();
}

while(true){
try {Thread.sleep(100);}
catch(Throwable t){}
}


Test2.java(静态内部类)

 公共类Test2 {
私人指针第一;

私有静态类指针{
公共指针接下来;
public Pointer(){
next = null;



public static void main(String [] args){
Test test = new Test();
指针[] p =新指针[1000];
for(int i = 0; i< p.length; ++ i){
p [i] = new Pointer();
}

while(true){
try {Thread.sleep(100);}
catch(Throwable t){}
}






$ b

当两者都运行时,你可以看到非静态占用比静态更多的堆空间。具体来说,非静态版本使用2,279,624 B,静态版本使用 10,485,760 1,800,000 B。

因此,它涉及的是非静态的内部类使用更多的内存,因为它包含对包含类的引用(至少)。静态内部类不包含此引用,所以内存永远不会分配给它。通过将你的堆大小设置得如此之低,你实际上是在颠簸你的堆,导致3倍的性能差异。


I just came across a weird effect and while tracking it down, I noticed that there seems to be a substantial performance difference for collecting inner vs. static nested classes. Consider this code fragment:

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;
            }
        }
    }
}

So what the code does is create a linked list using an inner class. The process is repeated 500 times (for testing purposes), discarding the objects used in the last run (which become subject to GC).

When run with a tight memory limit (like 100 MB), this code takes about 20 minutes to execute on my machine. Now, by simply replacing the inner class with a static nested class, I can reduce the runtime to less than 6 minutes. Here are the changes:

    private static class Pointer {

and

                Pointer p = new Pointer();

Now my conclusions from this little experiment are that using inner classes makes it much more difficult for the GC to figure out if the objects can be collected, making static nested classes more than 3x faster in this case.

My question is if this conclusion is correct; if yes what is the reason, and if no why are inner classes so much slower here?

解决方案

I would imagine this is due to 2 factors. The first one you already touched upon. The second is using non-static inner classes results in more memory usage. Why you ask? Because non-static inner classes also have access to their containing classes data members and methods, which means you are allocating a Pointer instance that basically extends the superclass. In the case of non-static inner classes you are not extending the containing class. Here is an example of what I'm talking about

Test.java (non-static inner class)

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) {}
        }
    }
}

Test2.java (static inner class)

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) {}
        }
    }
}

When both are run you can see the non-static taking up more heap space than the static. Specifically, the non-static version used 2,279,624 B and the static version used 10,485,760 1,800,000 B.

So, what it comes down to is the non-static inner class uses more memory because it contains a reference (at the very least) to the containing class. The static inner class doesn't contain this reference so the memory is never allocated for it. By setting your heap size so low you were actually thrashing your heap, which resulted in the 3x performance difference.

这篇关于内部类与静态嵌套类的GC性能相比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆