在Java语言中,判断一个内存空间是否符合垃圾回的标准有两个:
第一:给对象赋予了空值null,以后再没有被使用过;
第二:给对象赋予了新值,重新分配了内存空间。
一般来讲,内存泄漏主要有两种情况:
一是在堆中申请了空间没有被释放;
二是对象已不再被使用,但还仍然在内存中保留着。
垃圾回收机制的引入可以有效地解决第一种情况;而对于第二种情况,垃圾回收机制则无法保证不再使用的对象会被释放。因此Java语言中的内存泄漏主要指的第二种情况。
Java语言中,容易引起内存泄漏的原因有很多,主要有以下几个方面的内容:
(1)静态集合类,例如HashMap和Vector。如果这些容器为静态的,由于它们的声明周期与程序一致,那么容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。
(2)各种连接,例如数据库的连接、网络连接以及IO连接等。
(3)监听器。在Java语言中,往往会使用到监听器。通常一个应用中会用到多个监听器,但在释放对象的同时往往没有相应的删除监听器,这也可能导致内存泄漏。
(4)变量不合理的作用域。一般而言,如果一个变量定义的作用域大于其使用范围,很有可能会造成内存泄漏,另一方面如果没有及时地把对象设置为Null,很有可能会导致内存泄漏的放生,如下:
class Server{
private String msg;
public void receiveMsg(){
readFromNet();//从网络接收数据保存在msg中
saveDB()//把msg保存到数据库中
}
从上面的代码中,通过readFromNet()方法接收的消息保存在变量msg中,然后调用saveDB()方法把msg的内容保存到数据库中,此时msg已经没用了,但是由于msg的声明周期与对象的声明周期相同,此时msg还不能被回收,因此造成了内存泄漏。对于这个问题,有如下两种解决方案:第一种方法,由于msg的作用范围只在receiveMsg()方法内,因此可以把msg定义为这个方法的局部变量,当方法结束后,msg的声明周期就会结束,此时垃圾回收器就会可以回收msg的内容了;第二种方法,在使用完msg后就设置为null,这样垃圾回收器也会自动回收msg内容所占用的内存空间。
(5)单例模式可能会造成内存泄漏