java面试之简述一下 Java 垃圾回收机制?

**什么是垃圾回收机制:**在系统运行过程中,会产生一些无用的对象,这些对象占据着一
定的内存,如果不对这些对象清理回收无用对象的内存,可能会导致内存的耗尽,所以垃圾
回收机制回收的是内存。同时 GC 回收的是堆区和方法区的内存。
JVM 回收特点:(stop-the-world)当要进行垃圾回收时候,不管何种 GC 算法,除了垃圾回收
的线程之外其他任何线程都将停止运行。被中断的任务将会在垃圾回收完成后恢复进行。
GC 不同算法或是 GC 调优就是减少 stop-the-world 的时间。à(为何非要 stop-the-world),就像是一个同学的聚会,地上有很多垃圾,你去打扫,边打扫边丢垃圾怎么都不可能打扫干净的哈。当在垃圾回收时候不暂停所有的程序,在垃圾回收时候有 new 一个新的对象 B,此时对象 A 是可达 B 的,但是没有来及标记就把 B 当成无用的对象给清理掉了,这就会导致程序的运行会出现错误。
如何判断哪些对象需要回收呢:
**引用计数算法(java 中不是使用此方法):**每个对象中添加一个引用计数器,当有别人
引用它的时候,计数器就会加 1,当别人不引用它的时候,计数器就会减 1,当计数器为 0
的时候对象就可以当成垃圾。算法简单,但是最大问题就是在循环引用的时候不能够正确把
对象当成垃圾。
**根搜索方法(这是后面垃圾搜集算法的基础):**这是 JVM 一般使用的算法,设立若干
了根对象,当上述若干个跟对象对某一个对象都不可达的时候,这个对象就是无用的对象。
对象所占的内存可以回收。
根搜索算法的基础上,现代虚拟机的实现当中,垃圾搜集的算法主要有三种,分别是标记- 清除算法、复制算法、标记-整理算法。
**标记-消除算法:**当堆中的有效内存被耗尽的时候,就会停止整个系统,就会调用标记- 消除算法,主要做两件事,1 就是标记,2 就是清除。然后让程序恢复。
标记:遍历所有 GCroots 把可达的对象标记为存活的对象。
清除:把未标记为存活的对象清楚掉。
缺点:
就是效率相对比较低。会导致 stop-the-world 时间过长。
因为无用的对象内存不是连续的因此清理后的内存也不是连续的,(会产生内存碎片)因此
JVM 还要维持一个空闲列表,增加一笔开销,同时在以后内存使用时候,去查找可用的内存
这个效率也是很低的。
复制算法:(这个算法一般适合在新生代 GC),将原有的内存分为两块,每次只适用其中的一块,在垃圾回收的时候,将一块正在使用的内存中存活(上述根搜索的算法)的对象复制到另
一块没有使用的内存中,原来的那一块全部清除。与上述的标记-清除算法相比效率更高,
但是不太适合使用在对象存活较多的情况下(如老年代)。
**缺点:**每次对整个半区内存回收,因此效率比上面的要高点,同时在分配内存的时候不
需要考虑内存的碎片。按照顺序分配内存。简单高效。
但是最大的问题在于此算法在对象存活率非常低的时候使用,将可用内存分为两份,每次只
使用一份这样极大浪费了内存。
注意(重要):现在的虚拟机使用复制算法来进行新生代的内存回收。因为在新生代中绝大
多数的对象都是“朝生夕亡”,所以不需要将整个内存分为两个部分,而是分为三个部分,一
块为 Eden 和两块较小的 Survivor 空间(比例->8:1:1)。每次使用 Eden 和其中的一块 Survivor,
垃圾回收时候将上述两块中存活的对象复制到另外一块 Survivor 上,同时清理上述 Eden 和
Survivor。所以每次新生代就可以使用 90%的内存。只有 10%的内存是浪费的。(不能保证每
次新生代都少于 10%的对象存活,当在垃圾回收复制时候如果一块 Survivor 不够时候,需要
老年代来分担,大对象直接进入老年代)
标记-整理算法:(老年代 GC)在存活率较高的情况下,复制的算法效率相对比较低,同时还
要考虑存活率可能为 100%的极端情况,因此又不能把内存分为两部分的复制算法。
在上面标记-复制算法的基础之上,演变出了一个新的算法就是标记-整理算法。首先从
GCroots 开始标记所有可达的对象,标记为存活的对象。然后将存活的对象压缩到内存一端
按照内存地址的次序依次排列,然后末端内存地址之后的所有内存都清除。
**总结:**将标记存活的对象按照内存地址顺序排列到内存另一端,末端内存地址之后的内
存都会被清除。
**比较:**相比较于标记-清楚算法 (传统的),该算法可以解决内存碎片问题同时还可以解
决复制算法部分内存不能利用的问题。但是标记-整理算法的效率也不是很高。
->上述算法都是根据根节点搜索算法来判断一个对象是不是需要回收,而支撑根节点搜索算
法能够正常工作理论依据就是语法中变量作用域的相关内容。
三种算法比较:
**效率:**复制算法>标记-整理算法>标记-清除算法;
**内存整齐度:**复制算法=标记-整理算法>标记-清除算法
**内存利用率:**标记-整理算法=标记-清除算法>复制算法
分代收集算法:现在使用的 Java 虚拟机并不是只是使用一种内存回收机制,而是分代收集的算法。就是将
内存根据对象存活的周期划分为几块。一般是把堆分为新生代、和老年代。短命对象存放在
新生代中,长命对象放在老年代中。
对于不同的代,采用不同的收集算法:
**新生代:**由于存活的对象相对比较少,因此可以采用复制算法该算法效率比较快。
**老年代:**由于存活的对象比较多哈,可以采用标记-清除算法或是标记-整理算法
(注意)新生态由于根据统计可能有 98%对象存活时间很短因此将内存分为一块比较大的
Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor。当回收时,将
Eden 和 Survivor 中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉
Eden 和刚才用过的 Survivor 空间。
上述是垃圾回收机制的算法,但是垃圾回收器才是垃圾回收的具体实现:
常见有五个垃圾回收器:
一:串行收集器:(Serial 收集器)
该收集器最古老、稳定简单是一个单线程的收集器,(stop-the-world)可能会产生长时间
的停顿. serial 收集器一定不能用于服务器端。这个收集器类型仅应用于单核 CPU 桌面电脑。
新生代和老年代都会使用 serial 收集器。新生代使用复制算法(内存分三块的那个复制算法)。
老年代使用标记-整理算法。
二:并行收集器:(Parallel 收集器)
parallel 收集器使用多线程并行处理 GC,因此更快。当有足够大的内存和大量芯数时,parallel
收集器是有用的。它也被称为“吞吐量优先垃圾收集器。” 三:并行收集器:(Parallel Old 垃圾收集器)
相比于 parallel 收集器,他们的唯一区别就是在老年代所执行的 GC 算法的不同。它执行三
个步骤:标记-汇总-压缩(mark – summary – compaction)。汇总步骤与清理的不同之处在
于,其将依然幸存的对象分发到 GC 预先处理好的不同区域,算法相对清理来说略微复杂一
点。
四:并行收集器:(CMS 收集器)
(ConcurrentMark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。
适合应用在互联网站或者 B/S 系统的服务器上,这类应用尤其重视服务器的响应速度,希望
系统停顿时间最短。五:G1 收集器
这个类型的垃圾收集算法是为了替代 CMS 收集器而被创建的,因为 CMS 收集器在长时间
持续运行时会产生很多问题。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值