首先看一下下面两段代码有什么区别:
和
当时去问我们项目经理,他坚持认为这两种方式是一样的,个人习惯不同造成的不同写法而已。就功能上来说,都调用了test()函数,确实没什么区别,但是,如果考虑了内存回收,这两种写法就有很大的不同。
我们可以把这个例子更具体一点,如下:
第一种写法,在mark2处,A的内存已经可以被交给垃圾回收器回收了,也就是说在mark2处,可用内存和mark1处的可用内存完全相同。
第二种写法在mark 2处的可用内存和mark1处的可用内存是不同的,如果A类使用很大的空间,那么在mark2这里会抛出内存溢出异常,相反,第一种写法却没有这种问题。
下面的测试代码证明了两种写法的区别:
造成这种问题,主要还是java的内存回收机制,当java发现可用内存不足时,会调用内存回收器,内存回收器会去遍历当前线程栈,然后根据栈中的引用确定当前被使用的内存,将没有被遍历到的内存释放,在上面的例子中,b处于栈上,无法被回收,因此在c申请新内存是异常。b和c指向的内存要等到出了作用域(最近的大括号)才可以被回收。
这个问题解决后,马上又有一个新的问题,第一种写法中我们调用 new A().test(); 如果这个函数执行时间非常长,如何保证在执行过程中A的内存不会被回收(没有显式处于栈上的引用指向)。
考虑到c++的临时变量,所以猜想java的编译器会将new A().test();这段代码做如下处理:
在mark1处,从栈上分配temp引用指向堆中的A,之后,在mark2处,由于temp离开他自己的作用域,则栈上内存释放,也就是说栈上不再具有指向A的引用,使得A内存可被回收。
结论:
推荐使用 new A().test();这样的写法,在一定程度上可以节省当前内存。
(原文时间2013-1-30)