方法区:回收废弃常量和无用类
常见GC算法:
- 标记-清除(mark-sweeping)
两阶段:先标记再回收
缺点:
效率问题:标记和回收效率都不高,需要扫描所有对象。堆越大,GC越慢
空间问题:标记清理后会产生大量不连续的内存碎片,空间碎片太多可能会导致后续使用中无法找到足够多的连续内存而提前触发下一次的垃圾搜集动作 - 标记-压缩(mark-compact)
标记过程仍然一样,但后续步骤不是进行直接整理,而是令所有存活的对象一端移动,然后直接清理掉这端边界以外的内存
优点:没有内存碎片
缺点:比mark-sweep耗费更多的时间进行compact - 复制算法(copying)(现代商业虚拟机中都使用这种收集算法来回收新生代)
将可用内存划分为两块,每次只使用其中一块,当半区内存用完了,仅将还存活的对象复制到另一块上面,然后就把原来整块内存空间一次性清理掉
优点:只扫描存活的对象,效率更高 不会产生碎片
缺点:算法代价昂贵,需要将内存缩小为原来的一半
内存分为一块较大的eden空间和2块较少的survivor空间,每次使用eden和其中一块survivor,当回收时将eden和survivor还存活的对象一次性拷贝到另外一块survivor空间上,然后清理掉eden和用过的survivor
oracle hotspot虚拟机默认eden和survivor的大小比例是8:1,也就是每次只有10%的内存是浪费的
复制搜集算法在对象存活率高的时候,效率有所下降
如果不想浪费50%的空间,就需要额外的空间进行分配担保用于应付半区内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法 - 分代算法(generational)
一般把java堆分作新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法
内存回收:
GC要做的是将那些dead的对象所占用的内存回收掉
HotSpot认为没有引用的对象是dead的
HotSpot将引用分为四种:Strong Soft Weak Phantom
Strong即默认通过Object o=new Object()这种方式赋值的引用
Soft Weak Phantom这三种都是继承Reference
Full GC会对Reference类型的引用进行特殊处理
Soft:内存不够的时候一定会被GC、长期不用也会被GC
Weak:一定会被GC,当被mark为dead,会在ReferenceQueue中通知
Phantom:本来就没被引用,当从JVM heap中方释放时会通知