标题:
Java内存泄露的问题
[打印本页]
作者:
qingqing3721
时间:
2011-8-15 06:04
标题:
Java内存泄露的问题
Java内存泄露的成绩一 成绩的提出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进程顶点开始的一棵根树。在这个有向图中,根顶点可达的对象都是有效对象,GC将不回收这些对象。假设某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们以为这个(这些)对象不再被援用,可以被GC回收。以下,我们举一个例子说明如何用有向图表示内存管理。关于顺序的每一个时辰,我们都有一个有向图表示JVM的内存分配状况。以下右图,就是左边顺序运行到第6行的表示图。Java运用有向图的方式进行内存管理,可以消弭援用循环的成绩,例如有三个对象,互相援用,只需它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是运用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环援用的成绩),但执行效率很高。三 什么是Java中的内存泄露下面,我们就可以描画什么是内存走漏。在Java中,内存走漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即顺序以后不会再运用这些对象。假设对象满足这两个条件,这些对象就可以判定为Java中的内存走漏,这些对象不会被GC所回收,然而它却占用内存。在C++中,内存走漏的范围更大一些。有些对象被分配了内存空间,然后却不可达,由于C++中没有GC,这些内存将永远收不回来。
歌瑞尔
在Java中,这些不可达的对象都由GC担任回收,因此顺序员不需求考虑这局部的内存泄露。经过火析,我们得知,关于C++,顺序员需求自己管理边和顶点,而关于Java顺序员只需求管理边就可以了(不需求管理顶点的释放)。经过这种方式,Java进步了编程的效率。因此,经过以上分析,我们知道在Java中也有内存走漏,但范围比C++要小一些。由于Java从语言上保证,任何对象都是可达的,一切的不可达对象都由GC管理。关于顺序员来说,GC根本是透明的,不可见的。虽然,我们只有几个函数可以访问GC,例如运行GC的函数System.gc(),但是根据Java语言规范定义, 该函数不保证JVM的渣滓搜集器一定会执行。由于,不同的JVM实现者可能运用不同的算法管理GC。通常,GC的线程的优先级别较低。JVM调用GC的战略也有很多种,有的是内存运用到达一定水平时,GC才开始工作,也有定时执行的,有的是陡峭执行GC,有的是中断式执行GC。但通常来说,我们不需求关心这些。除非在一些特定的场所,GC的执行影照应用顺序的性能,例如关于基于Web的实时系统,如网络游戏等,用户不希望GC忽然中断应用顺序执行而进行渣滓回收,那么我们需求调整GC的参数,让GC可以经过陡峭的方式释放内存,例如将渣滓回收分解为一系列的小步骤执行,Sun提供的HotSpot JVM就支持这一特性。下面给出了一个复杂的内存泄露的例子。在这个例子中,我们循环申请Object对象,并将所申请的对象放入一个Vector中,假设我们仅仅释放援用本身,那么Vector依然援用该对象,所以这个对象对GC来说是不可回收的。因此,假设对象参加到Vector后,还必须从Vector中删除,最复杂的方法就是将Vector对象设置为null。Vector v=new Vector(10);for (int i=1;i100; i++){Object o=new Object();v.add(o);o=null;}//此时,一切的Object对象都没有被释放,由于变量v援用这些对象。
欢迎光临 编程开发论坛 (http://bbs.lihuasoft.net/)
Powered by Discuz! 6.0.0