关于java递归调用内存泄漏
来源:互联网 发布:贝叶斯分类算法过程 编辑:程序博客网 时间:2024/06/05 20:45
看两段代码:
import java.util.List;
public class TailRecursionTest {
public static void main(String[] args) {
TailRecursionTest t = new TailRecursionTest();
for (int i = 0; i < 10000; i++)
t.a(0);
}
public void a(int j) {
j++;
List list = new ArrayList<Integer>(100000);
// 对list进行处理
}
}
没啥特殊的,仅仅是为了测试,我们将a方法调用10000次,a方法创建一个有100000个元素的list的局部变量。
第二个程序:
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进行处理
a(j);
}
}
也没啥特殊的,就是将循环换成了递归,a方法做的事情没变。两个都跑一下,程序1顺利结束,程序2出问题了,啥问题?如下:
162
163
164
165
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.ArrayList.<init>(Unknown Source)
at TailRecursionTest2.a(TailRecursionTest2.java:17)
at TailRecursionTest2.a(TailRecursionTest2.java:20)
at TailRecursionTest2.a(TailRecursionTest2.java:20)
at TailRecursionTest2.a(TailRecursionTest2.java:20)
at TailRecursionTest2.a(TailRecursionTest2.java:20)
我倒,才运行166次了,heap就满了。问题在哪呢?oh,yep,你肯定想到了,是不是重复创建list这个大集合引起的呢?它不是局部变量吗?怎么也会溢出?是的,list是局部变量,在a的方法栈里引用着,指向heap上的大对象,更关键的问题在于,java是没有尾递归优化的,递归方法是不会使用同一个栈帧,每一次递归调用,都将压入新的栈帧,并且这个栈帧上又new了一个list变量,引用着heap上新的一个大集合。随着栈深度的增加, jvm里维持着一条长长的方法调用轨迹以便你能回来,在方法没有返回之前,这些list变量一直被各自的栈帧引用着,不能被GC,你说,能不OOM吗?
也许,你想到了个补救方法来挽救程序2,就是每次在处理完list后,我把它设置为null,不让栈帧继续引用着它,咱编写对gc友好的代码,这不就行了,试试:
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错误(OutOfMemory)和堆栈溢出的阴影将笼罩着你。
转载地址:http://www.enet.com.cn/article/2008/0613/A20080613294119.shtml
- 关于java递归调用内存泄漏
- 关于java递归调用内存泄露
- 关于java递归调用内存泄露
- 关于java递归调用内存泄露
- 关于Java内存泄漏
- 关于Java内存泄漏
- 关于java内存泄漏
- 关于Java的内存泄漏
- 关于JAVA内存泄漏问题注意事项
- 关于 JAVA 的内存泄漏问题
- 关于JAVA内存泄漏问题注意事项
- 关于Java内存泄漏的介绍
- 关于java内存泄漏的一点学习心得
- 关于Java内存泄漏及如何检测
- 关于gethostbyname_r调用后是否会有内存泄漏问题?
- 关于指针(内存)泄漏
- 关于查找内存泄漏
- 关于内存泄漏
- 当今国内最领先的网络舆情监控系统为你揭开神秘的面纱
- 实时布料模拟
- ibm相关产品的好地方
- 使用.NET/CLR的Stress Log功能寻找问题
- 操作系统实验环境搭建
- 关于java递归调用内存泄漏
- AIX 5.3L下安装GCC 4.2和G++ 4.2
- 个人简历(中英对照)词汇大全
- 使用Eric4+PyQt4制作一个简单的文本编辑器
- 网站加速--服务器编写篇(上)
- Wps和word共存
- jdk1.5新特性
- 网站加速--服务器编写篇 (下)
- asdfs