古老的回收算法
原理:通过记录并操作每个对象被引用的次数而控制GC
说明:
引用一次,次数加一。当对象的生命周期结束时,引用减一。当对象出了作用域后(该对象丢弃不再使用计数器减1)。此算法现已不再使用
缺点:无法循环处理引用
增量收集法(Incremental Collecting)。增量收集法是在应用,运行的时候运行算法进行垃圾回收,但是在JDK5以后不再使用该算法。
实现过程
这一阶段——标记,也就告诉我们,它将会遍历属于Java的内存空间
GC执行了这个算法之后,你以为它内存就回收完毕了?是回收完了,但是内存空间缺因这个而产生空间碎片,如下图。
在垃圾回收算法中,根是指向对象的指针的起点部分。
通过根对象进行引用搜索,最终可达的对象被称为可达对象(被引用对象);
通过根对象进行引用搜索,最终没有被引用的对象被称为不可达对象(即垃圾对象(不要理解歪咯哈哈哈))。
原因:对象占用内存空间不同而导致对象回收后空间呈碎片化。 你的对象所占用的内存大小又得根据你定义的对象具体内容来决定,因此这些碎片空间你是不能够利用到他们的特别是在进行大对象内存分配时,相较于连续内存空间,内存碎片的存在会降低堆内存效率因为Java内存空间的使用,并不一定是连续的,而且假如是连续使用了的空间,但在回收一部分未被(不可达)对象之后,他依然会产生这种空间碎片,这种空间碎片大小不一致,位置错乱分布。
打个比方:你的行李箱里面,如果你能规划好它的空间、安排好怎么放东西,便能使得空间利用率达到你所需要的最高,但是当你一股脑的往里面塞东西,往往它的容纳量是不尽你意的。
简述例子:划分好李箱空间,需要放的东西进行分类,以达到空间最大利用率。
多空闲链表
其实产生内存碎片和分配速度慢的主要原因是因为我们的只用到一条空闲链表的缘故。如果我们对块的大小进行分类:1字节的块放在 free_list_1, 2字节的块在free_list_2,… 直到free_list_100,对于100或100字节以上的块我们统一放到free_list_100里面。这样的话分配对象内存时就不用遍历整个链表而是根据大小到对应的具体的空闲链表,这样的时间会更快。并且因为作为大小区分,很多对象都能找到合适的块,有效的减少和避免了内存碎片的产生。这样的话内存碎片和分配速度慢的问题都可以得有效解决和缓解。
实现:
① 把内存空间划分为两个相等的区域,每次只使用其中一个区域
② GC时,遍历当前使用区域,将正在使用的对象复制到另一个区域中去并加以整理
③ 清除正在使用区的所有对象
④ 交换两个内存区
① 把内存空间划分为两个相等的区域,每次只使用其中一个区域
② GC时,遍历当前使用区域,将正在使用的对象复制到另一个区域中去并加以整理
③ 清除正在使用区的所有对象
④ 交换两个内存区
我们看图可以发现,尽管复制清除算法有效的处理空间碎片产生的问题,但是却导致有一半的内存空间是我们不能使用的。我感觉这里就好像是所谓“鱼和熊掌不可兼得”??
缺点:内存空间损失一半