万字详解JVM,让你一文吃透( 三 )


空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致,程序分配较大对象时无法找到足够的连续内存,不得不提前出发另一次垃圾收集动作 。

万字详解JVM,让你一文吃透

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

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

文章插图
分代收集算法根据对象的存活周期,将内存划分为几块 。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点,采用最适当的收集算法 。
  • 新生代:每次垃圾收集时会有大批对象死去,只有少量存活,所以选择复制算法,只需要少量存活对象的复制成本就可以完成收集 。
  • 老年代:对象存活率高、没有额外空间对它进行分配担保,必须使用“标记-清理”或“标记-整理”算法进行回收 。
Minor GC 和 Full GC有什么区别?Minor GC:新生代 GC,指发生在新生代的垃圾收集动作,因为 Java 对象大多死亡频繁,所以 Minor GC 非常频繁,一般回收速度较快 。Full GC:老年代 GC,也叫 Major GC,速度一般比 Minor GC 慢 10 倍以上 。
Java 内存为什么要将堆内存分区?对于一个大型的系统,当创建的对象及方法变量比较多时,即堆内存中的对象比较多,如果逐一分析对象是否该回收,效率很低 。分区是为了进行模块化管理,管理不同的对象及变量,以提高 JVM 的执行效率 。
堆内存分为哪几块?
  1. Young Generation Space 新生区(也称新生代)
  2. Tenure Generation Space养老区(也称旧生代)
  3. Permanent Space 永久存储区
分代收集算法内存分配有哪些原则?
  1. 对象优先分配在 Eden
  2. 大对象直接进入老年代
  3. 长期存活的对象将进入老年代
  4. 动态对象年龄判定
  5. 空间分配担保
Young Generation Space (采用复制算法)主要用来存储新创建的对象,内存较小,垃圾回收频繁 。这个区又分为三个区域:一个 Eden Space 和两个 Survivor Space 。