栈是由编译期确定内存分配,在线程执行完毕后即会清理,内存回收较容易,一般提到的内存回收是指回收堆中的内存
垃圾回收器当内存耗尽的时候工作,它工作时,一面回收空间,一面使堆中的对象更紧凑排列;通过垃圾回收器对对象进行重新排列,实现了一种高速的、有无限空间可供分配的堆模型
如何标记对象是否存活?
1、引用计数算法
每个对象都有一个引用计数器,当有引用连接至对象时引用计数器加1,当引用离开作用域或被置为Null时,引用计数减1,当发现某引用计数为0时,此对象无法再被使用,即为可回收对象
2、可达性分析算法
遍历所有对象,当在栈和方法区中找不到此对象的引用时,此对象无法再被使用,即为可回收对象
引用分为强、软、弱、虚四种
强引用:只要强引用还存在,该对象永远不会被回收;Object obj = new Object();
软引用:用来描述有用但非必须的对象.系统将要内存溢出时,将会把这些对象列入回收范围进行二次回收.如果还没有足够的内存,系统才会报内存溢出
弱引用:弱引用对象只能存活到下次内存回收发生之前.当发生内存回收时,无论内存是否足够,该对象均会被回收
虚引用:对象无论是否有虚引用存在均不会对其存在时间产生影响,也无法通过虚引用来获取对象实例.虚引用的唯一目的是当对象被回收时能收到一个系统通知
垃圾收集算法:
1、标记——清除算法
首先标记所有需要回收的对象(用上面的算法判断对象是否存活),标记完成之后统一回收所有被标记过的对象;但此方法效率不高,且会在内存中产生大量不连续的内存碎片
2、复制算法
把内存分为两块,每次只使用其中一块,当其中一块用完,则把存活的对象都复制到另一块内存,并把当前区域没存清空
虚拟机在新生代大多采取这种算法:首先把堆内存分为新生代、老年代两部分大小为1:2,此算法把新生代分为eden、from survivor、to survivor三部分,大小位8:1:1;创建新对象时,一般放在eden中,当eden内存用完时进行垃圾回收,把存活对象放到from survivor,并清空eden内存;当eden内存再次被用完时,把eden、from survivor中存活对象放到to survivor中,然后清除eden、from survovir;如此循环,对象每转移一次年龄加一,当年龄到达一定程度,默认15,此对象进入老年代.当survivor空间不足时,需要依赖老年代内存进行分配担保
参考:http://blog.csdn.net/hp910315/article/details/50985877
3、标识——清理算法
标记所有需要回收的对象,然后把存活的对象移到一端,再把需要回收的对象进行回收
4、分代收集算法
因新生代中每次垃圾回收只有少量对象存活,因此对新生代采用复制算法;
老年代中对象存活率高、没有担保空间,因此使用标记——清除或标记清理算法