黄忠的技术博客

永不停息的战争

Java内存泄露

  • 标签:
  • tec

我们Java程序员也经常提到内存泄露问题,当然对于C/C++来说,这个一点都不陌生。因为C/C++是程序员自己管理内存,Java内存是由GC自动回收的.

接下来,我们讨论一些具体问题。

什么是内存泄露?

内存泄露是指系统中存在无法回收的内存,有时候会造成内存不足或系统崩溃。
在C/C++中是指分配了内存而没有释放
在Java中是指存在无用但是垃圾回收器无法回收的对象

Java存在内存泄露?   

答案是肯定的,为了判断Java中是否有内存泄露,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放

1> 如何为对象分配内存

在Java中,通过关键字new为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。

2> 如何为对象释放内存

对象的释放是由GC决定和执行的。

也就是说内存的分配是由程序完成的,而内存的释放是由GC完成的,这种收支两条线的方法确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。
监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。

什么时候存在内存泄露

一般来说内存泄漏有两种情况,上面已经说的很明白:
##### 1> 一种情况如在C/C++语言中的,在堆中分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);

2> 另一种情况则是在内存对象已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。

第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。 可能光说概念太抽象了,大家可以看一下这样的例子:

```    
Vector v=new Vector(10);
for (int i=1; i<100;  i++) {
   Object o=new Object();
   v.add(o);
   o = null;
}
```

在这个例子中,代码栈中存在Vector对象的引用v和Object对象的引用o。在For循环中,我们不断的生成新的对象,然后将其添加到Vector对象中,之后将o引用置空。

问题是当o引用被置空后,如果发生GC,我们创建的Object对象是否能够被GC回收呢?答案是否定的。因为,GC在跟踪代码栈中的引用时,会发现v引用,而继续往下跟踪,就会发现v引用指向的内存空间中又存在指向Object对象的引用。也就是说尽管o引用已经被置空,但是Object对象仍然存在其他的引用,是可以被访问到的,所以GC无法将其释放掉。

如果在此循环之后,Object对象对程序已经没有任何作用,那么我们就认为此Java程序发生了内存泄漏。

参考

cowboy-bebop

分享到: 返回主页