不得不知道的Java内存溢出之在常常调用的方法内不要new大对象

不得不知道的Java内存溢出之在经常调用的方法内不要new大对象

        相信只要你看过Java的书,你一定会看到类似这样的话:千万不要假想内在处理器已经帮你把内存处理好了去做事。

        看过,真的就只是看过。和C还有C++相比,Java在大部分时间都可以省去了对内存的手动释放操作,不得不说,这个真的挺好使的,因为当初看C++的时候,用个数组,需要释放内在,真心闹不懂啊,这也是为什么当初没有真正走进编程世界的原因吧。

        但出来混,问题要还的。如果你代码写的不好,或者算法有问题,那么内存溢出的阴影就无时无刻不笼罩你。前两天,就因为自己懒而遇到了内在溢出的问题。

        上篇文章说到了递归调用,下面看下我遇到问题的核心算法:

import(ListOfElement){
	for(iterator iter=ListOfElement.iterator();iter.hasNext();){
		Element ele=iter.next();
		Object o=Xml2Obj(ele);	//Xml2Obj是一个将Element转成Obj的方法
		addObject(o);  //注意这行代码调用的方法
		if(ele.elements()!=null && ele.elements().size()>0){
			import(ele.elements());
		}
	}
}
addObject(object){
	List list=object.getSomething();
	do others
}

        网上说递归调用容易造成内在溢出,后来我改成了非递归,如下:

import(ListOfElement){
	Queue queue=new LinkedList();	//采用Java里面的队列(LILO)
	for(iterator iter=ListOfElement.iterator();iter.hasNext();){
		queue.add(iter.next());
		while(!queue.isEmpty()){
			Element ele=queue.poll();  //poll和remove的区别是如果为空,remove会抛异常,而poll返回空
			Object o=Xml2Obj(ele);
			addObject(o);  //注意这行代码调用的方法
			if(ele.elements()!=null && ele.elements().size()>0){				
				for(iterator iterChild=ele.elements();iterChild.hasNext){
					queue.add(iterChild.next());
				}
			}
		}
	}
}

        但是,受伤并没有好一些,内存溢出依然存在,心都碎了。后来又在网上找内存溢出的原因,一个一个的进行了对比,发现有人说不要在经常调用的方法里创建对你,尤其是循环里。

        这点说的不就是我么?那个addObject经常被调用,而且new了一个比较大的对象(List),并且还是在循环里,然后我就把这个List手动释放了一下,注意,List的释放需要先调用clear,然后再把其设置成null,如下:

addObject(object){
	List list=object.getSomething();
	do others
	list.clear();
	list=null;
}

        现在,再运行发现很快就执行完成,并且内存也没有用多少。于是又实验了一下:改回递归,而这个方法内存释放,发现依然内存溢出。这也就说明了递归调用确实容易造成内存溢出。

        通过这个例子,想说明的是:当你发现内存溢出后,不要第一时间就是加内存,造成内存溢出最大的可能就是你的代码没有优化,也通过这个问题让我又重新温习了一下那好久没有翻过的数据结构与算法。

        最后,向大家推荐一下让我找到思路的博客注意Java内存泄漏。同时也推荐大家没事的时候,将看看数据结构与算法这本书,真的很好~~~