Java 虚拟机JVM 总结(精简版) [下] |
四、垃圾收集器
1. Serial 收集器 算法:堆内存年轻代采用“复制算法”;堆内存老年代采用“标记-整理算法”。👳👞🪜💩🤙 单线程收集器,只会使用一个 CPU 或一条收集线程去完成垃圾收集工作。 垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束(又称为「Stop The World」)。 优点是简单而高效(与其他收集器的单线程相比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然就可以获得最高的单线程收集效率。 2. ParNew 收集器 💅🏦🥩♂🐞 算法:堆内存年轻代采用“复制算法”。 ParNew 收集器就是 Serial 收集器的多线程版本。 只能用于新生代。 多线程收集,并行。 👆⛄🥩🆒🕊 在多 CPU 环境下,随着 CPU 的数量增加,它对于 GC 时系统资源的有效利用是有益的。它默认开启的收集线程数与 CPU 的数量相同。ParNew收集器在单CPU的环境中绝对不会有比Serial收集器有更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个 CPU 的环境中都不能百分之百地保证可以超越。 3. Parallel Scavenge 收集器 👆🌕🫑📶🐡 算法:堆内存年轻代采用“复制算法”;配合收集器:ParallelOldGC,堆内存老年代采用“标记整理算法”。 多线程收集器。 只适用于新生代。 自适应调节策略。👨🚒👓🧲😀🤟 Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。 Parallel Scavenge 收集器无法与 CMS 收集器配合使用。 4. CMS 收集器 🧒👓📡🤔🤌 4.1 运作过程 初始标记 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要“Stop The World”。 并发标记 🦷🏫🍒🈷🐻 进行 GC Roots 追溯所有对象的过程,在整个过程中耗时最长 重新标记 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。此阶段也需要“Stop The World”。 🧒👖✒🙂🦴 并发清除 特点 Concurrent Mark Sweep,基于“标记-清除”算法实现。 各阶段耗时:并发标记/并发清除 > 重新标记 > 初始标记。 对 CPU 资源非常敏感。 🤳🛩🥩🈴🦦 标记-清除算法导致的空间碎片。并发收集、低停顿,因此 CMS 收集器也被称为并发低停顿收集器。 无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次 Full GC 的产生。 由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作;所以,从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。 👍❌🦬 5. G1 收集器 运作过程 初始标记 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要“Stop The World”。 👂⛴🍭♻🦌 并发标记 进行 GC Roots 追溯所有对象的过程,可与用户程序并发执行。 最终标记🧓👞🪦😃👍 修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录。 筛选回收 对各个Region的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来指定回收计划。 👁🗼🍇🆗🪶 特点空间整合:整体上看来是基于“标记-整理”算法实现的,从局部(两个Region)上看来是基于“复制”算法实现的。 面向服务端应用的垃圾收集器。 并行与并发。🩰📀😇👀 分代收集。 可预测的停顿:G1收集器可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java的垃圾收集器的特征。 G1将整个Java堆(包括新生代、老年代)划分为多个大小相等的内存块(Region),每个Region是逻辑连续的一段内存,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域。 五、问题总结🧑🍳👔🖌😥👍 1. 局部变量表与操作数栈有什么区别? 局部变量表是存放编译器可知的各种基本数据类型、对象引用类型和方法返回地址;通过索引访问;局部变量表所需内存空间在编译期已确定大小。 操作数栈是工作区,在这里进行根据指令对数据进行压栈、出栈进行数据运算;通过出栈入栈方式访问。 👨⚕️🧦🛋🥰👍 2. StackOverflowError 与 OutOfMemoryError 的区别? StackOverflowError 是指栈请求的深度大于虚拟机规定的栈深度,此时内存空间可能还足够。 OutOfMemoryError 是指内存空间不足,无法分配内存。🩲🖥😥🦷 3. 内存泄漏和内存溢出的区别? 申请内存后,无法释放已申请的内存空间,内存泄漏堆积的结果是内存溢出。 内存溢出是指申请内存时,没有足够的内存空间供申请者使用。 🖕🛩🍇🈸🐅 4. 符号引用和直接引用的区别? 符号引用是字面量,用符号来描述引用目标,只包含语义信息,与具体实现无关。 直接引用是与具体实现息息相关,是直接指向目标的指针。 🧒👖🖲😆🤝 5. 常量池和运行时常量池的区别? 常量池存在于静态的存储文件中,Java 中表现为 .class 文件,主要包含字面量和符号引用。 👄🗺🍏↔🐟 运行时常量池存在于内存中,是常量池被加载到内存之后的版本,并且字面量可以动态添加,比如 String.intern() 6. Minor GC 与 Full GC 的区别 Minor GC 称为新生代GC,是发生在新生代的垃圾回收动作,因为 Java 对象绝大多数具备朝生夕灭的特性,Minor GC 触发非常频繁,并且回收速度很快。 👂⛄🦀🆎 Full GC 称为老年代GC,发生在老年代,出现了 Full GC,通常会伴随一次 Minor GC。Full GC 的速度一般比 Minor GC 慢 10 倍以上。
帖子热度 8490 ℃
手摘星辰认真回帖,奖励 1 个 金币.
|
|
苍天有眼,让偶等到了!楼主此贴必然会起到抛砖引玉的作用,我更坚信在有生之年必然会看到有更多象楼主一样的人来八卦畅所欲言、发表高见,不管明天会是如何,今夜梦中,我会笑容灿烂,因为,我终于知道了,此番人世,得此一贴,无憾矣!
|