java会出现内存泄漏吗?


======================================================
注:本文源代码点此下载
======================================================

首先,我们先介绍heap和stack这两个概念

stack的中文意思是栈,保存着基本类型和引用变量,当程序运行到这些变量的作用域之外,就会被释放。

heap的中文意思是堆,在c语言中,malloc函数分配的内存就是堆内存,c++和java中new出的对象和数组也会放到堆中,堆中的变量不会随着程序的执行而释放。

java中采取了gc机制,帮助我们自动释放一些堆内存中无关的引用对象。而在c/c++中需要程序员手动的释放,从这个意义上来说很多书上都说java避免了内存泄漏。

其实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;i<100; i++)

{

object o=new object();

v.add(o);

o=null;

}

//此时,所有的object对象都没有被释放,因为变量v引用这些对象。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值