Java 的内存泄漏
简介:Java 的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的
回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认为 Java 不存在内存泄
漏问题,或者认为即使有内存泄漏也不是程序的责任,而是 GC 或 JVM 的问题。其实,这
种想法是不正确的,因为 Java 也存在内存泄露,但它的表现与 C++不同。
问题的提出
Java 的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管
理内存的回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认
为 Java 不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的责任,而
是 GC 或 JVM 的问题。其实,这种想法是不正确的,因为 Java 也存在内存泄
露,但它的表现与 C++不同。
随着越来越多的服务器程序采用 Java 技术,例如 JSP,Servlet,EJB 等,服
务器程序往往长期运行。另外,在很多嵌入式系统中,内存的总量非常有限。
内存泄露问题也就变得十分关键,即使每次运行少量泄漏,长期运行之后,系
统也是面临崩溃的危险。
Java 是如何管理内存
为了判断 Java 中是否有内存泄露,我们首先必须了解 Java 是如何管理内存的。
Java 的内存管理就是对象的分配和释放问题。在 Java 中,程序员需要通过关
键字 new 为每个对象申请内存空间(基本类型除外),所有的对象都在堆
(Heap)中分配空间。另外,对象的释放是由 GC 决定和执行的。在 Java 中,
内存的分配是由程序完成的,而内存的释放是有 GC 完成的,这种收支两条线
的方法确实简化了程序员的工作。但同时,它也加重了 JVM 的工作。这也是
Java 程序运行速度较慢的原因之一。因为,GC 为了能够正确释放对象,GC
必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,
GC 都需要进行监控。
监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就
是该对象不再被引用。
为了更好理解 GC 的工作原理,我们可以将对象考虑为有向图的顶点,将引用
关系考虑为图的有向边,有向边从引用者指向被引对象。另外,每个线程对象
可以作为一个图的起始顶点,例如大多程序从 main 进程开始执行,那么该图
就是以 main 进程顶点开始的一棵根树。在这个有向图中,根顶点可达的对象