日期:2013-07-07  浏览次数:20393 次

转载自【雨声论坛】
原作:software_young

----------------------转载开始------------------------
所谓垃圾回收机制,指的是内存和各种变量或者目标所使用内存的释放和回收机制。

软件的发展历史,就是软件不断庞大、人力逐渐难以控制和对开发人员的技术要求逐渐降低的历史。

早先的许多软件,都是用汇编语言写的,汇编是机器码的助记符方式,因此,用汇编编程,实际就是用机器码编程。它要求程序员对机器非常熟悉才行,否则很难编出能用的程序。

那时候的程序员首先要是铁算盘,需要对机器的运行状态完全成竹在胸,脑子里对CPU的各个寄存器的值,状态寄存器的状态,栈内的BP、SP,内存的分配和释放以及其他一些东西非常清楚才行。他掌握了机器(哪怕只是虚拟机)的全部资源的使用和释放,因此那时候,没有所谓的垃圾回收机制。程序员可以说就是高级机器人,他管理一切。

随着软件技术的发展,高级语言开始出现,软件也逐渐变得庞大起来,主要的高级语言都有了专门用于分配和释放内存和变量、目标(对于面向目标的编程语言来说)的函数或者功能。

程序员用它们来负责内存的分配和释放。但是逐渐地,高级机器人也感到难以应付了,于是出现了内存丢失的问题,就是内存分配后忘记释放了。

一般来说,操作系统记录了进程所使用的资源,在进程结束时释放这些资源。但是如果进程运行的时间很长,或者永不结束(主机和小型机经常是常年运行的),操作系统就没有机会来及时地释放这些资源,从而造成系统内存的丢失。系统内存的丢失积累到一定的程度,怪事就该出现了。

这个问题实际是人脑和电脑复杂度的比较问题。不幸的是,人脑注定要输给电脑(在某些方面)。这就要求系统提供一种机制来统一管理和回收垃圾。

不同语言和系统的垃圾回收机制是不同的。

C语言实际没有垃圾回收机制,一切依赖程序员和操作系统。如果编写的程序忘记释放内存而又长时间的运行,麻烦就来了。而如果编译器本身的库函数有问题,那就更可怕了。Borland的C/C++编译器经常有这个问题,业界很多人都知道的,因此很少有人敢用它来做大的软件。

C++语言在类的析构函数中提供垃圾回收,由程序员决定释放那些资源,当程序调用某个类的析构函数时,垃圾回收工作执行并完成。这实际上任然是程序员控制的方式。

Java则提供了独立的垃圾回收机制,它无需程序员的介入,由Java虚拟机来决定何时进行垃圾回收。当然程序员在一定情况下可以强制垃圾回收机制立即工作,方法是调用system.gc下面的几个方法(具体查书)。

具体的实现分为两大部分,一部分是如何确定哪些是垃圾,另一部分是如何回收。

在第一部分中有两大类方法,第一种是所谓的引用计数法,引用计数为零的自然是垃圾了,这种方法很简单,但是无法处理相互引用的问题;第二种是所谓的顺藤摸瓜法,因为Java所有的东西无非两大类,目标和非目标,目标存在堆中,非目标存在栈中,栈的先进后出方式决定了不会有垃圾问题,而所有的目标都是Object的某代后代。从头摸起,就可以确定谁是好人(有人要的,有领导的),谁是坏蛋(没有人要的,没有领导的),将坏蛋处理就是了。

第二部分又分成两大类,同步和异步。

所谓同步就是在某一时刻所有的处理暂停,作垃圾回收,然后再继续暂停的处理。这种方法很简单,但是会造成系统性能的颠簸。

所谓异步就是分成两步走,先暂停处理,进行标记;然后将系统分区,按分区分别处理坏蛋,这种方法的好处是系统性能的颠簸会减少,缺点是由于同步的问题,可能放过坏人。

PC上一般使用同步的方法,因为PC上的应用一般不太大,系统颠簸的影响不大。AS/400上一般使用异步的方法,和AS/400的系统特点(多个子系统)相结合,可以将不足降到最小,当然AS/400也可以使用同步的方法,这可以在WebSphere for AS/400中进行设置。

.Net的垃圾回收机制和Java的非常相似,这里就不赘述了。


software_young 编辑于 2002-02-01 13:55
----------------------转载结束------------------------