JAVA 提供垃圾回收器释放内存,防止内存泄露,无需程序员手动释放内存,减轻了编码的负担。那么它究竟是如何工作呢,今天就和大家一探究竟。
我们先来看看 C++ 是如何释放内存的,C++ 里每个对象都负责管理自己的内存,通过析构函数释放内存,倘若程序员未执行析构函数,则内存在程序终止之前,永远不会得到释放,易造成内存泄露。
在 JAVA 中有一个特殊的函数 finalize() ,在对象被垃圾回收器清理之前,会被调用。但需特别注意的是,调用 finalize() 不一定立马会被垃圾回收器清理,只有当程序无法获得足够的内存时,才会被清理。通常可以使用 finalize() 来进行对象终结条件的验证,例如:一个对象打开了一个文件,在对象被清理时,验证文件是否被关闭。
接下来,来实际看看垃圾回收器是如何工作的。JAVA 对象存放于堆中,通过“堆指针”来为对象分配内存空间,每分配一个新对象,指针就往前移动一格,分配的速度非常快,但内存资源是有限的,当内存资源即将耗尽时,垃圾回收器便会介入。
垃圾回收器一边回收空间,一边将堆中的对象紧凑排列,实现了一种高速、有无限空间可供分配的堆模型。
JAVA 的垃圾回收器是如何辨别需要回收的对象呢?
当一个对象不再被其他对象引用的时候,就会被列入垃圾回收的名单。
不同的 JAVA 虚拟机拥有不同的垃圾回收模式:
1.停止–复制模式(stop-and-copy)
先暂停程序的运行(不能在后台进行回收),将所有存活的对象从当前堆复制到另一个堆中,未被复制的对象,会被当做垃圾进行回收,复制到新堆的对象会被紧凑排列。
这种模式效率较低,至少得保持两个堆进行复制,还得多维护一倍的内存空间。此机制无法在前台运行,程序在此期间会被暂停运行。
2.标记–清扫模式(mark-and-sweep)
每找到一个活的对象,就会给对象一个标记,此时不会清理任何对象。当全部标记工作完成时,清理动作才会开始执行,没有标记的对象会被释放,不会发生任何复制动作,但剩下的堆空间不连续,此模式也无法在后台运行,程序会被暂停运行。
3.自适应模式
内存分配以“块”为单位,对象较大则占用单独的块,对象较小则共用一个块,每个块上都拥有相应的代数来记录对象是否存活。如果“块”新增一个引用,则“块”上的“代数”就加一;减少一个引用,“块”上的“代数”减一。对大对象的块使用“标记–清扫模式”(减轻维护堆空间的压力),对小对象共用的块使用“停止–复制模式”(对处理临时短命对象大有提升),倘若垃圾回收器的效率降低,则仅仅会使用“标记–清扫模式”。
本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。
若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!