62,629
社区成员
发帖
与我相关
我的任务
分享
我同意你的说法,那个栈实现的pop代码之所以有内存泄露问题,正是因为疏忽了栈的pop()的本意,本意应该是:既然弹出元素,那被弹出的元素就应该马上让系统回收,而不仅仅只是减小一下栈顶指示index, 设想如果在往这个栈中推入大量对象,导致系统内存逼近可用极限时,(但还没到极限),紧接着如果作者按原pop()这样弹出全部元素但不释放内存,然后作者以为因为“我已经把栈内元素全部弹出了啊!这样被占堆内存应该大幅度下降了,所以,我就可以放心的再做别的使用大量堆内存的其他代码了,(与这个栈的无关,但需要大量堆内存的代码),他很可能马上发现,其实,pop全部栈元素根本没有起到释放内存的效果,堆内存仍然极为紧张,再分配大量堆内存马上报内存溢出,这就是因为pop()内少了一句:elements[size] = null;
而这段有问题的代码之所以在无限循环重复做:先推入栈,后再弹出,再推入。。。。的测试中没有报错,是因为:在第二次重复推入栈的时候,同一位置引用指向新的new BigObj(), 失去引用的第一次入栈的对象被jvm发现而垃圾回收啊!因祸得福啊! 但是这个是jvm的功劳,如果是c/c++实现,重复推入,弹出,再推入,。。。就没有这么好的运气了,因为c/c++没这个发现失去引用的对象自动回收的功能。
总之,原来的栈实现pop函数的确有内存泄露问题,只是碰巧在做无限循环重复做:先推入栈,后再弹出,再推入的测试中,因为jvm的功能而没被发现罢了! 不过,要求effecitve java的作者再这样举出一个无限循环反复推入,弹出,再推入的例子,然后说明这段代码尽管有问题,但却没有异常以及原因,似乎对作者的要求高了些!是不是? 作者太尽心了,哈哈!
以上,是我的理解,不知哪位高人有更好,更高的斧正?
我的main()测试函数:
public static void main(String[] args) {
int loop = 160;
Stack stack = new Stack();
while(true) {
for (long i = (long) 0; i < loop; i++) {
BigObj object = new BigObj();
stack.push(object);
}
System.out.println("pop from stack----------------");
for (long i = 0; i < loop; i++) {
stack.pop();
}
}
}public static void main(String[] args) {
Stack stack = new Stack();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Object object = new Object();
stack.push(object);
}
}