1.如何判定对象为垃圾对象?或者jvm如何判断对象是否失效?
引用计数法
在对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器的值就+1,当引用失效的时候,计数器的值就-1。
引用计数法实现简单,判定效率高。可能堆里几个内存块相互引用,这样虽然是垃圾,但是引用计数法却不能判断此为垃圾,因为它们相互引用,计数不为0。具体如下图:
可达性分析法:
可达性分析法虽然相比较引用计数法会复杂一点,但是可以解决引用计数法的问题。
可达性算法的核心算法是从 GC Roots 对象作为起点往下搜索,当一个对象到 GC Roots 不存在任何引用链时,则此对象不可活。当对象不可活时,还可通过finalize()方法自救。
可作为 GC Roots 的对象包括:1.方法区中常量引用的对象 2.方法区中静态属性引用的对象 3.虚拟机栈中引用的对象 4.本地方法中引用的对象。
2.简述你知道的垃圾回收算法。
垃圾回收算法有:标记清除算法,标记整理算法,复制算法,分代收集算法。
a.标记-清除算法:先利用可达性分析算法,标记出存活的对象。标记完之后,再扫描整个空间中未被标记的对象进行回收。 缺点:效率低,会造成大量碎片。
b.标记-整理算法:在标记-清除算法的基础上,执行完标记清除全过程之后,再一次对内存进行整理,将所有存活对象统一向一端移动,这样解决了内存碎片问题。–老年代对象
c.复制算法:复制算法将空间分为两部分,每次使用其中的一部分。当一块内存用完了,就将这一块所有存活对象复制到另一块,将已使用的块清除。不会产生碎片,但会浪费一定的内存空间。在堆中的年轻代使用该算法,因为年轻代多为生命周期较短的对象。年轻代将内存分为一个Eden, 两个Suvivor, 一个Survivor0,一个Survivor1。首先使用Eden, 当Eden内存占满时将存活对象复制到Survivor0,同时清空Eden。当Suvivor0内存也满时,就复制Eden和Suvivor0的存活对象到suvivor1,然后清空Eden和Suvivor0。然后互换Suvivor0和Suvivor1的角色,保持Suvivor1为空。当Suvivor1放不下Suvivor0和Eden的存活对象时,则需要老年代的空间担保。
d.分代收集算法:根据新生代,老年代的特点采用不同的算法。新生代对象的存活周期较短,所以采用复制算法。老年代对象存活周期较长,所以采用标记-整理算法。
3.垃圾收集器:
垃圾收集器可以分为回收新生代和回收老年代两种类型收集器。其中回收新生代收集器有 Serial、PraNew、Parallel Scavenge,回收老年代的收集器有 Serial Old、Parallel Old、
CMS,还有用于回收整个 Java 堆的 G1 收集器。
Serial 收集器(复制算法):新生代单线程收集器,在进行垃圾回收时需要停止其他的所有
工作线程
Serial Old收集器(标记-整理):老年代单线程收集器,Serial的老年代版本
ParNew 收集器:新生代并行收集器,实际是 Serial 收集器的多线程版本,
cms是老年代的并行收集器,如果使用cms收集老年代的,必须要使用parNew或者serial。
Parallel Scavenge收集器:新生代并行收集器,追求高吞吐量。
CMS 收集器:老年代里面的唯一一个基于标记-清除算法,它是老年代并行收集器。
G1 收集器:唯一一个可以同时用于年轻代和老年代的垃圾收集器。
4.垃圾回收对象时程序的逻辑是否可以继续执行?
不同回收器不同:Serial、ParNew会暂停用户所有线程工作;CMS、G1会在某一阶段暂停用户线程。
5. 内存分配策略?
1.对象优先在Eden分配:若Eden无空间,Java虚拟机发起一次Minor GC。
2.大对象直接进入老年代:大对象指需要大量连续内存空间的对象(如长数组、长字符串)
3.长期存活的对象进入老年代:每个对象有一个对象年龄计数器,age=15晋升为老年代。age+1的两个情况