垃圾回收

来源:互联网 发布:mysql的面试题及答案 编辑:程序博客网 时间:2024/04/28 07:17

个人认为垃圾回收机制是java语言最棒的功能之一。正是有垃圾回收机制的存在,使得java程序员不必要费心考虑内存泄漏问题(当然还是有内存泄漏的可能性存在的),这不仅仅是少写一句delete()的问题。java语言的垃圾回收机制是和java的单根继承体系以及对象空间分配等机制紧密联系的。可以说是java语言整个的体系结构造就了这么出色的垃圾回收机制。至于c++,Bjarne Stroustrup在他的faq中提及垃圾回收的问题。他声称现在有一些不错的商业的和公共域的垃圾回收器,而且在垃圾回收器适用的程序中C++的垃圾收集和其他支持垃圾收集的语言相比性能更好。另外C++还支持其他内存管理技术,不用垃圾收集也可以安全地隐式地管理内存。可惜自己c++太菜了,要努力学习,好好研究一下。

垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。java程序员不需要考虑太多内存的管理,虚拟机会自动在内存紧张的时候进行垃圾回收的操作。释放资源的同时,垃圾回收机制也会清楚内存中的碎片。这个功能可以提升对象空间分配的效率,因为垃圾回收会将内存中的对象紧密排列,新对象的分配只要将堆指针简单前移就行了,不需要遍历堆来查找合适大小的内存块。这样java在堆中分配空间的效率甚至可以逼近在栈中的分配效率。

但是垃圾回收在释放资源的时候仍然会占用大量资源。效率的高低与垃圾回收机制所使用的算法有关系。

垃圾回收最单纯直观的算法就是引用计数法。每个对象都有一个引用计数表。增加一个对该对象的引用,计数加一,反之减一。垃圾回收的时候,即将引用计数为0的对象释放。这种算法速度很慢。因为垃圾回收器要遍历内存中的所有对象,并在发现引用计数为零的时候将其释放。另外对于循环交互引用的一群对象,如果整群对象都已经成为垃圾,那么仍然有可能存在非零的计数。所以引用计数几乎没有被用于任何真正的虚拟机上。

实际中使用的算法是:从栈和静态存储空间中的reference出发,访问他们指向的对象,以及这些对象内部引用到的对象。整个过程中访问到的对象即还存活的对象,未访问到的自然成了垃圾。在处理对象的时候,有众多的机制。其中主要的是“stop-and copy”,“mark and sweep”和“generation”。

stop-and-copy即将找到的对象从正在执行的程序中停下来,然后copy到新的堆中。同时将对该对象的reference指向新的地址。这种做法使得对象在新堆中排列紧凑。但是也存在若干的问题。这种机制要维护两个堆,对象在两个堆之间copy,因此使用该机制要占用的内存是实际需要的两倍。另外,若程序只产生很少的垃圾,而垃圾回收仍然会将对象copy到新堆中,严重影响了程序的执行效率。

mark and sweep也是从栈和静态存储空间出发,对找到的对象进行标记。整个标记过程结束后再进行清理,没有标记的对象将被清理。这种方式会产生不连续的内存块。要使得内存排列紧密,必须重新进行整理工作。以上的两种做法都要在中止程序的情况下进行。

generation方法将内存分成若干的大块,称为generation。每块中会有世代纪录。新出现的块更“年轻”。每次垃圾回收之后,将年轻块中存活的对象移到比该块年长的块中。这种方法适用于处理数量极大而生命短暂的小对象。比较稳定的对象会处于年长的块中,不会被复制,只会改动其世代纪录。

虚拟机通常采用自省式的垃圾处理机制。他会根据当时的内存情况选择适当的垃圾回收机制。比如内存对象稳定时即采用mark-and-sweep,减少copy次数。如果内存中碎片过多,即采用stop-and-copy的方法使内存紧凑。