what is garbage?
例如
引用计数法
python使用。
没有引用计数时,该堆空间成为垃圾
有毛病
如果垃圾之间相互引用,成为一堆垃圾,却没有其他的任何引用,这种方式就找不出来。
根可达算法
java使用
树的搜索算法,
从main的变量开始。
说白了,就是一个线程(的main方法)最开始创建的那些对象。就是root, 就是根.
清除算法
Mark-Sweep(标记清除)
逻辑简单, 但是有毛病, 碎片化严重
Copying(拷贝)
复制一份root能搜索到的到另一片内存, 原来这边全不要.
逻辑简单, 也没有碎片化, 但是浪费内存.
Mark-Compact(标记压缩)
吸取以上两种的毛病, 边找到可用的内存, 边排列好, 不会有碎片化内存, 也不浪费空间, 但是效率低.
从上世纪60年代开始, 到今天, 就这三种.
java的垃圾回收机制
java从1.0开始, 到14
一共出现过10种垃圾回收机制
事实上, 对于垃圾回收而言是跟着内存的改变而改变的. 随着硬件技术的进步, 内存变得越来越大, 相应的垃圾回收机制就也要跟着进步.
总的来说, 就是垃圾回收机制都有毛病, 所以一般都很聪明的使用对内存分区的方法, 将垃圾回收的三种算法综合来使用.
内存的分代模型
从java开始到java8
都一直在使用
也就是说, 将内存进行分区.
大体分为新生代和旧生代的两个地方
对于新生代对象而言, 回收机制每进来扫描一次, 就是增长一岁, 到了一定的阈值, 就会被copy进旧生代, 在新生代被清除.
这样一来, 对于新生代和旧生代的两种对象, 就可以使用不同的清除算法, 大大的提高了效率.
例如: 对于旧生代, 我可以前期进行Mark-Sweep, 效率极高, 后面我发现碎片化太严重了, 我就使用Mark-compact进行一次整理.
到目前为止, jdk1.8
的垃圾回收机制, 叫做ppo
也是用的这种分代模型
事实上只要内存不是特别大, 分代模型是可以的
历史演变:从单线程到多线程(并非越多越好)再到和业务并发, 出现CMS, 理解三色标记, 并知道CMS有天生的不足, 有可能漏扫.
cms分四个阶段:
找到root
并发标记(三色)
黑色: 子对象全部扫过
灰色: 自身扫过, 子没扫完
白色: 没能扫到.
remark
清除
G1
终于放弃了分代模型
因为随着内存的增大, 就算再怎么并发, 时间依然是跟不上.
现在叫分区算法