【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列( 二 )


newObject()反映到 Java 堆中,形成一块存储了 Object 类型所有对象实例数据值的内存 。Java堆中还包含对象类型数据的地址信息 , 这些类型数据存储在方法区中 。
如何判断对象是否“死去”?

  1. 引用计数法
  2. 根搜索算法
什么是引用计数法?给对象添加一个引用计数器,每当有一个地方引用它,计数器就+1,;当引用失效时,计数器就-1;任何时刻计数器都为0的对象就是不能再被使用的 。
引用计数法的缺点?很难解决对象之间的循环引用问题 。
什么是根搜索算法?【【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列】通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的 。
【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列

文章插图
Java 的4种引用方式?在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为
  1. 强引用 Strong Reference
  2. 软引用 Soft Reference
  3. 弱引用 Weak Reference
  4. 虚引用 Phantom Reference
强引用Object obj =newObject();代码中普遍存在的,像上述的引用 。只要强引用还在 , 垃圾收集器永远不会回收掉被引用的对象 。
软引用用来描述一些还有用,但并非必须的对象 。软引用所关联的对象,有在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围,并进行第二次回收 。如果这次回收还是没有足够的内存,才会抛出内存异常 。提供了 SoftReference 类实现软引用 。
弱引用描述非必须的对象,强度比软引用更弱一些,被弱引用关联的对象,只能生存到下一次垃圾收集发生前 。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象 。提供了 WeakReference 类来实现弱引用 。
虚引用一个对象是否有虚引用,完全不会对其生存时间够成影响,也无法通过虚引用来取得一个对象实例 。为一个对象关联虚引用的唯一目的,就是希望在这个对象被收集器回收时,收到一个系统通知 。提供了 PhantomReference 类来实现虚引用 。
有哪些垃圾收集算法?
  1. 标记-清除算法
  2. 复制算法
  3. 标记-整理算法
  4. 分代收集算法
标记-清除算法(Mark-Sweep)什么是标记-清除算法?分为标记和清除两个阶段 。首先标记出所有需要回收的对象,在标记完成后统一回收被标记的对象 。
有什么缺点?效率问题:标记和清除过程的效率都不高 。
空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致,程序分配较大对象时无法找到足够的连续内存,不得不提前出发另一次垃圾收集动作 。
【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列

文章插图
复制算法(Copying)- 新生代将可用内存按容量划分为大小相等的两块,每次只使用其中一块 。当这一块的内存用完了,就将存活着的对象复制到另一块上面 , 然后再把已经使用过的内存空间一次清理掉 。
优点复制算法使得每次都是针对其中的一块进行内存回收,内存分配时也不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效 。
缺点将内存缩小为原来的一半 。在对象存活率较高时 , 需要执行较多的复制操作,效率会变低 。
【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列

文章插图
应用商业的虚拟机都采用复制算法来回收新生代 。因为新生代中的对象容易死亡,所以并不需要按照1:1的比例划分内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间 。每次使用 Eden 和其中的一块 Survivor 。
当回收时 , 将 Eden 和 Survivor 中还存活的对象一次性拷贝到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间 。Hotspot 虚拟机默认 Eden 和 Survivor 的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80% + 10%),只有10%的内存是会被“浪费”的 。
标记-整理算法(Mark-Compact)-老年代标记过程仍然与“标记-清除”算法一样 , 但不是直接对可回收对象进行清理,而是让所有存活的对象向一端移动 , 然后直接清理掉边界以外的内存 。

推荐阅读