关于java递归调用内存泄漏

发表于:2008-7-31 16:30

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:本站原创

        我倒,才运行166次了,heap就满了。问题在哪呢?oh,yep,你肯定想到了,是不是重复创建list这个大集合引起的呢?它不是局部变量吗?怎么也会溢出?是的,list是局部变量,在a的方法栈里引用着,指向heap上的大对象,更关键的问题在于,java是没有尾递归优化的,递归方法是不会使用同一个栈帧,每一次递归调用,都将压入新的栈帧,并且这个栈帧上又new了一个list变量,引用着heap上新的一个大集合。随着栈深度的增加, jvm里维持着一条长长的方法调用轨迹以便你能回来,在方法没有返回之前,这些list变量一直被各自的栈帧引用着,不能被GC,你说,能不OOM吗?

        也许,你想到了个补救方法来挽救程序2,就是每次在处理完list后,我把它设置为null,不让栈帧继续引用着它,咱编写对gc友好的代码,这不就行了,试试:
import java.util.ArrayList;  
import java.util.List;  
 
public class TailRecursionTest2 {  
    public static void main(String[] args) {  
        TailRecursionTest2 t = new TailRecursionTest2();  
        t.a(0);  
    }  
 
    public void a(int j) {  
        System.out.println(j);  
        j++;  
        if (j == 10000)  
            return;  
        List list = new ArrayList<Integer>(100000);  
        // 对list进行处理  
        list = null;  //gc友好  
        a(j);  
    }  
}

        得意洋洋,我跑一下看看,这次跑到4000多次,但是:
4289 
4290 
4291 
4292 
java.lang.StackOverflowError  
    at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source)  
    at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)  
    at java.nio.charset.CharsetEncoder.encode(Unknown Source)


        总结:在java里,递归最好咱还是别用,老老实实地while、for;就算递归了,最好递归方法不要new太大的对象,除非你能确定递归的深度不是那么大,否则OOM和堆栈溢出的阴影将笼罩着你。


22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号