Java中内存泄露及垃圾回收机制_第1页
Java中内存泄露及垃圾回收机制_第2页
Java中内存泄露及垃圾回收机制_第3页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第 30 卷第 2 期唐 山 师 范 学 院 学 报2008 年 3 月vol.30 no.2 journal of tangshan teachers college mar. 2008 收稿日期: 2007-03-20 作者简介:张学红(1978-) ,男,河北滦县人,助教,工学学士,现从事计算机程序语言科研工作。- 80 -java中内存泄露及垃圾回收机制张学红,李小慧,杜瑞庆(唐山师范学院计算机科学系,河北唐山 063000 )摘要:java语言中,内存空间中垃圾回收的工作由垃圾回收器(garbage collector,gc)完成, gc 可以有效地减少内存泄露发生的概率,但它的启动

2、无规律可循,因此不能完全避免内存泄露。通过分析产生内存泄露的原因,提出了java编程中的一些注意事项,有效地避免了内存泄露。关键词: java;内存泄露;垃圾回收器;虚拟机中图分类号: tp312 文献标识码: a 文章编号: 1009-9115(2008)02-0080-03 memory leaks in java and garbage collector zhang xuehong, li xiaohui, du ruiqing (department of computer science, tangshan teachers college, hebei tangshan, 063

3、000, china) abstract:in java language, garbage collector (gc) is responsible for collecting garbage in memory. gc can reduce occurrence of memory leaks effectively, but its work has no rules, so it cant avoid memory leaks entirely. having analyzed the reasons of memory leaks, several suggestions wer

4、e put forwarded in java programming which can avoid memory leaks effectively. key words: java; memory leaks; garbage collector; virtual machine java 是一种可以编写跨平台应用软件的面向对象的程序设计语言,由sun microsystem 公司的詹姆斯高斯林等人于 20 世纪 90 年代初开发。伴随着java技术的普及,网络上越来越多的服务器程序采用java技术,特别是internet使 java 成为网上最流行的编程语言。在传统的高级编程语言(例

5、c+)中,对象的创建和回收均由程序员自行负责,如果创建了对象而忘记回收,则会造成内存泄漏, 长此以往,程序运行的时候可能会生成很多不清除的垃圾,浪费了不必要的内存空间,有时还可能引起系统的崩溃。在java 中,引入了垃圾回收机制: 垃圾回收器 (garbage collector, gc) ,可以自动回收内存中的垃圾,这是java 语言相对于其它语言的优势,但是内存泄漏并不会因此而完全避免。1 内存泄露大多数 c+编译器不支持垃圾回收机制。通常使用 c+编程的时候, 程序员所创建的对象在创建时在堆栈上分配一块内存地址, 当不需要这个对象,进行析构或者删除的时候再释放分配的内存空间。如果对象是在

6、堆上分配了,而程序员又忘记进行释放,这些空间又无法自动回收,就会造成内存泄漏。而无法回收的内存空间,即丢失的内存(称为“垃圾” ) ,除非是重新启动系统否则永远也不会还给操作系统。长此以往, 程序运行的时候可能会生成很多垃圾,浪费了不必要的内存空间。 更糟糕的是, 如果同一内存地址被删除两次的话,程序会变得不稳定,甚至崩溃。java语言则不同, 上述的情况被自动垃圾回收机制自动处理。对象的建立和放置都是在内存堆栈上面进行的。程序或者其他的对象可以锁定一块堆栈地址来进行其他对象的引用。当一个对象没有任何引用的时候,java的自动垃圾回收机制就发挥作用,自动删除这个对象所占用的空间,释放内存以避免

7、内存泄漏。 但是内存泄漏并不是就此而完全避免了,当程序员疏忽大意地忘记解除一个对象不应该有的引用的时候, 内存泄漏仍然不可避免,不过发生的几率要比不启用垃圾回收机制的c+程序少很多。 但是总体来讲, 自动垃圾回收机制要安全和简单许多。2 垃圾回收机制张学红,等:java 中内存泄露及垃圾回收机制- 81 -2.1 什么是垃圾垃圾,内存中的垃圾, 即内存中已无效但又无法自动释放的空间。在java 语言中,没有引用句柄指向的类对象最容易成为垃圾。产生垃圾的情况有很多,主要有以下3 种:(1)超出对象的引用句柄的作用域时,这个引用句柄引用的对象就变成垃圾。例 1 person p1 = new pe

8、rson(); 引用句柄 p1的作用域是从定义到“”处,执行完这对大括号中的所有代码后,产生的person对象就会变成垃圾,因为引用这个对象的句柄p1已超过其作用域, p1 已经无效,person对象不再被任何句柄引用了。(2)没有超出对象的引用句柄的作用域时,给这个引用句柄赋值为空时,这个引用句柄引用的对象就变成垃圾。图 1 柄赋值为空的引用的对象变成垃圾例 2 person p1 = new person(); . p1 = null; . 在执行完“ p1=null; ”后,即使句柄p1 还没有超出其作用域,仍然有效,但它已被赋值为空,不再指向任何对象,则这个 person 对象不再被任

9、何句柄引用,变成了垃圾。此后 p1 还可以指向其它person对象,因为还没有超出它的作用域。(3)创建匿名对象时,匿名对象用完以后即成垃圾。例 3 new person(); /因为是匿名对象,没有引用句柄指向它,即为垃圾new person().print(); / 当运行完匿名对象的print() 方法,这个对象也变成了垃圾 因此,在程序中应尽量少用匿名对象。2.2 垃圾回收在 java 程序运行过程中,一个垃圾回收器(garbage collector ,简称gc)会不定时地被唤起检查是否有不再被使用的对象, 并释放它们占用的内存空间。垃圾回收器的回收无规律可循, 可能在程序的运行的过

10、程中,一次也没有启动,也可能启动很多次。因此,并不会因为程序代码一产生垃圾,垃圾回收器就马上被唤起而自动回收垃圾,很可能到程序结束时垃圾回收器都没有启动。所以垃圾回收器并不能完全避免内存泄漏的问题。另一方面, 垃圾回收会给系统资源带来额外的负担和时空开销。它被启动的几率越小,带来的负担的几率就越小。因此,垃圾的回收策略也很重要。2.3 垃圾回收器的回收策略不同厂商、不同版本的java 虚拟机中的内存垃圾回收机制并不完全一样,通常越新版本的内存回收机制越快。而不同的 java 虚拟机采用不同的回收策略,常用的有两种:复制式回收策略和自省式回收策略。复制式回收策略: 先将正在运行中的程序暂停,然后

11、把正在被使用的所有对象从它们所在的堆内存a 里复制到另一块堆内存b,再释放堆内存a 中的所有空间, 这些不再使用的对象所占用的内存空间就会被释放掉。这种方式需要维护所需内存数量的至少两倍的内存空间,适合垃圾比较多的情况。当程序只产生了少量垃圾或者没有垃圾时,这种回收策略的效率就非常低。自省式回收策略: 首先检测所有正在使用的对象,并为它们标注, 比如用 1 来标注正在使用的对象,用 0 来标注不再被使用的对象,然后将所有标注为0 的内存空间一次释放。因为标注会增大系统的开销,因此这种方式的速度仍然很慢,尤其是在垃圾比较多的情况下,效率会很低。这种方法适合垃圾比较少的情况。这两种方式具有互补性,

12、因此在一些java 虚拟机中两种方式被有机的结合运用。3 system.gc() 由于 java 的垃圾回收器的启用不由程序员控制,而且回收也无规律可循,并不会一产生了垃圾,垃圾回收器就被唤起;有时甚至可能到程序终止,回收器都没有启动的机会。因此这个垃圾回收机制不是一个很可靠的机制。因为垃圾不能及时回收, 它们所占用的内存空间不能释放,就会影响程序的性能; 如果某段程序产生大量的垃圾而没有回收,回收工作也会变得困难。为了解决这个问题,java 提供一个system.gc()方法,可以强制启动垃圾回收器来回收垃圾,以减少内存泄露发生的概率。例 4 匿名对象会产生垃圾,如果担心这些垃圾不能及时回收

13、,可以在使用完这些匿名对象以后,加上一条语句:system.gc(),强制启动垃圾回收器来回收垃圾。第 30 卷第 2 期唐 山 师 范 学 院 学 报 2008年 3 月- 82 - class testjc public void finalize() system.out.println(free the occupied memory.); public static void main(string args) new testjc(); new testjc(); new testjc(); system.gc(); system.out.println(end of progra

14、m.); 程序的运行结果如图2 所示。图 2 例 4 运行结果system.gc()有一个特点,就是在对象被当成垃圾从内存中释放前要调用finalize()方法,而且释放一个对象调用一次finalize()方法。从程序的运行结果可以看到:垃圾回收器启动以后,并不一定马上回收垃圾,很可能要等待一段时间才执行。这是因为在程序运行过程中,垃圾收集线程优先级比较低,如果有比这个线程优先级高的线程,先运行这些优先级高的线程,等这些线程执行完毕,才进行垃圾回收。所以system.gc()方法只是一种 “建议”,它建议 java虚拟机执行垃圾回收,释放内存空间,但不能够预知什么时候能够回收。如果把“syst

15、em.gc();”语句, 放在第二个匿名对象语句后面,再进行编译和执行,其结果将如图3 所示。图 3 “system.gc();”在第二个匿名对象语句后运行结果这是因为, 启动完垃圾回收器以后,它只能检测到在垃圾回收器强制启动之前程序运行所产生的垃圾,java的虚拟机尽最大的努力从被丢弃的对象上回收垃圾;对于在启动垃圾回收器以后产生的垃圾,这个线程检测到的概率就非常小了,如果检测不到,就不能回收这些垃圾。因此,java中的垃圾回收器机制及system.gc()方法,并不能够完全避免内存泄露的问题,只是尽可能降低内存泄露的可能性和程度。4 java 编程中需要注意的事项为了提高垃圾的回收效率,在

16、实际应用中, 使用下列几种方法可以在一定程度上避免java中的内存泄露。(1) 尽量少用匿名对象,慎用内部类匿名对象被使用完以后就会变成垃圾;而在内部类中,隐含着一个外部类对象的引用,这个引用也无法自动消除。(2) 在 使用system.gc()方 法的 程序 中,尽 量少用finalize() 方法。因为system.gc()方法在回收每一个对象所占用的内存空间时, 都会调用 finalize() 方法,在这个方法中的任何操作都会增加垃圾回收的开销。(3) 慎用 system.gc()方法,减少线程的个数在程序中可以显式地调用system.gc()方法,但这种方法不能保证清除所有的垃圾。另外垃圾回收也是一个线程,也会消耗系统的资源,启动垃圾回收也可能会造成间歇性停顿。线程越多,垃圾回收线程挂起和恢复的可能性就越大,而耗费的时间就越长,系统的开销就越大。5 结语对 java 的内存泄漏和垃圾回收机制进行了论述,分析了内存泄露的原因以及system.gc()的工作方式, 提出了一些避免内存泄露的方法。 参考文献 1 张孝祥 .java 就业培训教程m. 清华大学出版社

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论