java内存泄露:Java内存泄露的问题

Java内存泄露问题

问题提出

Java个重要优点就是通过垃圾收集器(Garbage CollectionGC)自动管理内存回收员不需要通过来释放内存因此很多员认为Java不存在内存泄漏问题或者认为即使有内存泄漏也不是责任而是GC或JVM问题其实这种想法是不正确Java也存在内存泄露但它表现和C区别

随着越来越多服务器采用Java技术例如JSPServlet EJB等服务器往往长期运行另外在很多嵌入式系统中内存总量非常有限内存泄露问题也就变得十分关键即使每次运行少量泄漏长期运行的后系统也是面临崩溃危险

2 Java是如何管理内存

为了判断Java中是否有内存泄露我们首先必须了解Java是如何管理内存Java内存管理就是对象分配和释放问题在Java中员需要通过关键字为每个对象申请内存空间 (基本类型除外)所有对象都在堆 (Heap)中分配空间另外对象释放是由GC决定和执行在Java中内存分配是由完成而内存释放是有GC完成这种收支两条线思路方法确实简化了工作但同时它也加重了JVM工作这也是Java运行速度较慢原因的GC为了能够正确释放对象GC必须监控每个对象运行状态包括对象申请、引用、被引用、赋值等GC都需要进行监控

监视对象状态是为了更加准确地、及时地释放对象而释放对象根本原则就是该对象不再被引用

为了更好理解GC工作原理我们可以将对象考虑为有向图顶点将引用关系考虑为图有向边有向边从引用者指向被引对象另外每个线程对象可以作为个图起始顶点例如大多进程开始执行那么该图就是以进程顶点开始棵根树在这个有向图中根顶点可达对象都是有效对象GC将不回收这些对象如果某个对象 (连通子图)和这个根顶点不可达(注意该图为有向图)那么我们认为这个(这些)对象不再被引用可以被GC回收

以下我们举个例子介绍说明如何用有向图表示内存管理对于个时刻我们都有个有向图表示JVM内存分配情况以下右图就是左边运行到第6行示意图


Java使用有向图方式进行内存管理可以消除引用循环问题例如有 3个对象相互引用只要它们和根进程不可达那么GC也是可以回收它们这种方式优点是管理内存精度很高但是效率较低另外种常用内存管理技术是使用计数器例如COM模型采用计数器方式管理构件它和有向图相比精度行低(很难处理循环引用问题)但执行效率很高

3 什么是Java中内存泄露

下面我们就可以描述什么是内存泄漏在Java中内存泄漏就是存在些被分配对象这些对象有下面两个特点首先这些对象是可达即在有向图中存在通路可以和其相连;其次这些对象是无用以后不会再使用这些对象如果对象满足这两个条件这些对象就可以判定为Java中内存泄漏这些对象不会被GC所回收然而它却占用内存

在C内存泄漏范围更大有些对象被分配了内存空间然后却不可达由于C中没有GC这些内存将永远收不回来在Java中这些不可达对象都由GC负责回收因此员不需要考虑这部分内存泄露

通过分析我们得知对于C员需要自己管理边和顶点而对于Java员只需要管理边就可以了(不需要管理顶点释放)通过这种方式Java提高了编程效率

因此通过以上分析我们知道在Java中也有内存泄漏但范围比C要小Java从语言上保证任何对象都是可达所有不可达对象都由GC管理

对于员来说GC基本是透明不可见虽然我们只有几个可以访问GC例如运行GC.gc但是根据Java语言规范标准定义不保证JVM垃圾收集器定会执行区别JVM实现者可能使用区别算法管理GC通常GC线程优先级别较低JVMGC策略也有很多种是内存使用到达定程度时GC才开始工作也有定时执行是平缓执行GC是中断式执行GC但通常来说我们不需要关心这些除非在些特定场合GC执行影响应用性能例如对于基于Web实时系统如网络游戏等用户不希望GC突然中断应用执行而进行垃圾回收那么我们需要调整GC参数让GC能够通过平缓方式释放内存例如将垃圾回收分解为系列小步骤执行Sun提供HotSpot JVM就支持这特性

下面给出了个简单内存泄露例子在这个例子中我们循环申请Object对象并将所申请对象放入个Vector中如果我们仅仅释放引用本身那么Vector仍然引用该对象所以这个对象对GC来说是不可回收因此如果对象加入到Vector后还必须从Vector中删除最简单思路方法就是将Vector对象设置为null

Vector v= Vector(10);
for ( i=1;i<100; i)
{
Object o= Object;
v.add(o);
o=null;
}
//此时所有Object对象都没有被释放变量v引用这些对象

4 如何检测内存泄漏

最后个重要问题就是如何检测Java内存泄漏目前我们通常使用些工具来检查Java内存泄漏问题市场上已有几种专业检查Java内存泄漏工具它们基本工作原理大同小异都是通过监测Java运行时所有对象申请、释放等动作将内存管理所有信息进行统计、分析、可视化开发人员将根据这些信息判断是否有内存泄漏问题这些工具包括Optimizeit ProfilerJProbe ProfilerJinSight , Rational 公司Pury等

下面我们将简单介绍Optimizeit基本功能和工作原理

Optimizeit Profiler版本4.11支持ApplicationAppletServlet和Romote Application 4类应用并且可以支持大多数类型JVM包括SUN JDK系列IBMJDK系列和JbuilderJVM等并且该软件Software是由Java编写因此它支持多种操作系统Optimizeit系列还包括Thread Debugger和Code Coverage两个工具分别用于监测运行时线程状态和代码覆盖面

当设置好所有参数了我们就可以在OptimizeIt环境下运行被测运行过程中Optimizeit可以监视内存使用曲线(如下图)包括JVM申请堆(heap)大小和实际使用内存大小另外在运行过程中我们可以随时暂停运行甚至强行GC让GC进行内存回收通过内存使用曲线我们可以整体了解使用内存情况这种监测对于长期运行应用非常有必要也很容易发现内存泄露


在运行过程中我们还可以从区别视角观查内存使用情况Optimizeit提供了 4种方式:

堆视角 这是个全面视角我们可以了解堆中所有对象信息(数量和种类)并进行统计、排序过滤了解相关对象变化情况
思路方法视角通过思路方法视角我们可以得知每种类对象都分配在哪些思路方法中以及它们数量
对象视角给定个对象通过对象视角我们可以显示它所有出引用和入引用对象我们可以了解这个对象所有引用关系
引用图 给定个根通过引用图我们可以显示从该顶点出发所有出引用

在运行过程中我们可以随时观察内存使用情况通过这种方式我们可以很快找到那些长期不被释放并且不再使用对象我们通过检查这些对象生存周期确认其是否为内存泄露在实战当中寻找内存泄露是件非常麻烦事情它需要员对整个代码比较清楚并且需要丰富调试经验但是这个过程对于很多关键Java都是十分重要

综上所述Java也存在内存泄露问题其原因主要是些对象虽然不再被使用但它们仍然被引用为了解决这些问题我们可以通过软件Software工具来检查内存泄露检查主要原理就是暴露出所有堆中对象员寻找那些无用但仍被引用对象
Tags:  什么是内存泄露 vc内存泄露 内存泄露 java内存泄露

延伸阅读

最新评论

发表评论