Java老师在期末复习大纲上出了一道关于JVM垃圾回收机制的题目,想要我们简述一下JVM垃圾回收机制,与老师交流后,大概老师是希望通过与其他语言在垃圾回收对比,介绍一下Java在这方面的特点和处理过程,这里我搜索到一篇差不多内容的论文,这篇论文在内容上讲的很浅,没有深入到源码和内部算法,大致了解一下即可。
在运用面向对象语言编写的程序中,当某些对象不再被引用的时候,内存回收它占领的空间,以便空间能够被后来的新对象所使用,以免造成内存泄露。C++与 Java 是这些年较为流行的面向对象语言,Java是由 C++发展出来的。 内存泄漏一般来讲主要有两种情况:第一种情况是在堆中分配的内存,在没有将其释放的时候,就将能访问这块内存的方式删掉;第二种情况是在内存对象已经不需要的时候,仍旧保留着内存和它的访问方式。 而出现第一种情况多是在 C++中,指针是C++中一种内置的数据类型,且发生的原因是所使用的指针出现了重新赋值的情况;第二种情况多出现在 Java 中,这也是 Java 内存泄露的主要情况。
垃圾回收机制是一种动态的存储技术,它能够自动释放不再被程序引用的对象,按照特定的垃圾回收算法实现系统资源自动回收的功能。
Java 是一种跨平台,适合于分布式计算环境的纯面向对象编程语言。 在 Java 中,程序员是通过关键字 new 来创建对象以及在堆(Heap)中为对象分配内存空间(基本数据类型除外),而对象的释放是由 GC(Garbage Collection,垃圾回收器)决定和执行的。这种收支两条线在很大程度上简化了程序员的工作, 但 也 加 重 了 JVM (Java VirtualMachine,Java 虚拟机)的工作。 Java 并没有明确指明 JVM 在进行垃圾回收时使用哪种垃圾回收算法,但是不管采用那种垃圾回收算法均要完成发现无用对象并回收被无用对象占用的内存空间的功能。 Java 中对内存对象的访问采用的是引用方式,当 GC 跟踪到某个对象没有被
任何线程访问时,该对象就要被删除,就将其加入到垃圾回收队列,但是进行垃圾回收的线程是一种低优先级的系统级线程,为此系统并不会马上进行对象的消除, 而何时消除并释放内存是无法预知的。 在Java 中一般是在 CPU 空闲或者是空间不足时自动进行垃圾回收,对于程序员来讲, 是无法精准的控制垃圾回收的时机和回收的顺序,哪怕是 Java 虚拟机抛出 OutOfMemoryError 异常, 或者是程序员调用了System.gc()方法请求 JVM 进行垃圾回收。
C++也是一种面向对象语言,但由于兼容了 C 我们通常认为它是一种半面向对象语言。 在 C++中内存的分配主要有三种方法:1)全局变量和静态变量存储在静态存储区中,生存的周期就是程序运行的周期,即当程序结束,才释放这些存储空间;2)函数内部的局部变量存储在栈上,生存的周期就是该变量所在函数的运行周期,即函数调用结束后,这些存储空间自动释放。3)动态分配存储空间,在 C 语言中通过malloc,free 来完成内存空间的分配与释放, 在 C++中通过 new,delete来完成内存空间的分配与释放, 生存周期是由 new 和 delete 来决定的。
在 C++中程序员运用 new 实现动态分配内存空间,分配后就需要负责这块内存的整个生命周期。 从分配到使用再到最后的释放,这样的过程显的很灵活,但同时也十分繁琐,程序员很容易由于某种原因而忘记释放内存,从而导致内存的泄露。 而 C++不像 Java 那样有 GC自动实现垃圾回收,但为我们提供了智能指针来解决内存问题。 智能指针是一种像指针的 C++对象,它能够在对象不使用的时候自己销毁掉。
在 C++标准库(std)中提供了一种智能指针 auto_ptr,实际上该智能指针是一种模板类,其工作原理是:通过 new 来分配内存空间构造一个对象,通过自动调用析构函数来完成对这段内存的释放。 具体的实现是:auto_ptr 在构造时获取对某个对象的所有权,在析构时释放该对象,这样可以提高代码的安全性。
例如:
int * p=new int();
auto_ptrap(p);
智能指针 ap 获取了 p 的所有权, 从此我们不必关心应该何时释放 p, 更不用担心发生异常会有内存泄漏。 auto_ptr 智能指针使用简单,方便灵活,除了在定义的时候与普通指针有一点区别以外,其他具体的使用与普通指针是一样的,但是 auto_ptr 智能指针不能将数组作为参数以及不能将 auto_ptr 对象作为标准模板库(STL)容器的元素使得它的使用并不是很广泛。
Boost 库 是 为 C++语言标准库提供扩展的一些 C++程序库的 总称 ,Boost 库为我们定义了多个不同智能指针来 管理不同的场景 ,shared_ptr 是使用最广泛的智能指针。 shared_ptr 智能指针在内部维护一个引用计数器, 当有指针指向这块内存区域时引用计数器加 1,反之减 1, 若没有任何指针指向引用计数器为 0, 则释放内存区域。shared_ptr 指针可以实现共享和转移所有权, 同时它可以被 STL 的容器所使用,这一点与 auto_ptr 指针不同,还有一个更大的特点就是适合管理对象被若干个对象共享的复杂问题。 scoped_ptr 是 Boost 库中最简单的智能指针,当指针离开作用域时释放相关的资源,该指针不能共享指针的所有权也不能转移所有权,即内存地址只能给声明的变量使用而不能给其他使用。 Boost 库还有很多其他智能指针,这里不再一一叙述,总之在 C++中不论使用标准库中的智能指针,还是 Boost 库中的智能指针,在一定的条件下可以实现垃圾回收,同时智能指针使用起来比较简单,能够有效地解决内存泄露问题。
【参考文献】
[1]Java 内存分配与释放[OL]. http://wenku.baidu.com/view/c124098ccc22bcd126f
f0cd4.html.
[2]全面分析 Java 的垃圾回收机制[OL]. http://tech.qq.com/a/20060726/000329.htm.
[3]陈龙得,毕海滨.浅谈在 C++中如何实现垃圾自动回收[J].电脑知识与技术,
2008,7:2007-2008.
[4]C++Boost 库中的智能指针论 [OL]. http://blog.sina.com.cn/s/blog_6eb6c 4590
100n74y.html.
作者简介:王艳娟(1979—),女,济南职业学院教师。