1. 对象内存布局
一个对象本身的内存结构需要一种描述方式,这个描述信息(类描述)是以字节码的方式存储在方法区的,虚拟机使用对象头的元数据指针指向定位到当前对象的具体目标类型(类对象)。对象头的Mark word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳、对象分代年龄。实例数据主要用于存储定义在当前对象中各种类型的字段信息(包括派生于超类的字段信息)。
2. GC性能衡量
吞吐量:程序的运行时间/(程序的运行时间+内存回收时间);
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间;
收集频率:相对于应用程序的执行,收集操作发生的频率;
3. 垃圾标记:根搜索算法
引用计数算法当死亡对象之间相互引用时,引用计数器的值永远不会为0,这样将导致GC永远无法释放掉无用对象所占用的内存空间,极有可能引发内存泄露。根搜索算法不仅同样具备实现简单和执行高效等特点,还可以解决死亡对象相互引用问题。根搜索算法是以根对象集合作为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达,如果目标对象不可达时,就意味着该对象已经死亡,便可以在instanceOopDesc的Mark Word中将其标记为垃圾对象。
根对象集合所存储的内容:Java栈中的对象引用、本地方法栈中的对象引用、运行时常量池中的对象引用、方法去中类静态属性的对象引用、类对应的Class对象
4. JVM常用的三种垃圾收集算法
标记——清除算法 复制算法 标记——压缩算法
标记__清除算法分为垃圾标记和内存释放两个阶段执行,不仅执行效率低下,因为无用对象所占用的内存空间可能不连续,不可避免的会产生一些内存碎片,导致后续没有足够的内存空间分配给较大的对象。
复制算法即当执行一次新生代的垃圾回收(Minor GC)时,Eden空间与From空间中的存活对象会被复制到To空间,当To空间的容量达到阈值或存活对象分代年龄超过指定阈值时,存活对象也会进入到老年代中,完成复制或晋升操作后,剩下的均为垃圾对象,此时GC可以对这些死亡对象执行一次Minor GC,释放其所占用的内存空间,然后将From空间和To空间互换位置。
标记__压缩算法(老年代的垃圾回收)在成功标记处java堆区老年代的垃圾对象后,该算法会将所有的存活对象都移动到一个规整且连续的内存空间中,然后执行Full GC回收无用对象所占用的内存空间,执行压缩后使用指针碰撞的内存分配方式为新对象分配内存。
5. 新生代与老年代垃圾回收算法特性
新生代选择的垃圾收集算法通常速度优先,因为所存储的对象生命周期短暂,可以针对性的使用复制算法,回收频繁。
老年代通常使用更节省内存的回收算法,对象生命周期长,并且老年代占据了大部分的堆空间,所以老年代回收并不频繁,而且每一次Full GC将会耗费很长的时间来完成。
6. 垃圾收集器
串行回收:Serial收集器采用复制算法、串行回收和暂停机制,用于新生代。而Serial Old采用了标记__压缩算法,用于老年代。
并行回收:ParNew收集器使用也复制算法,用于新生代。
程序吞吐量优先:Parallel收集器,采用并行回收,复制算法,可以控制程序的吞吐量大小,用于新生代。
低延迟:CMS收集器是一款优秀的老年代收集器,为并发而生,采用标记清除算法,包括初始标记、并发标记、再次标记与并发清除阶段,确保垃圾对象都能被正确标记。