JVM垃圾处理机制

Posted Kirl z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM垃圾处理机制相关的知识,希望对你有一定的参考价值。

1. 内存溢出和内存泄漏

1.1 内存溢出

创建变量/对象/类加载, 需要先在对应的内存区域, 分配一块内存空间, 如果该区域内存不足, 需要执行 gc (垃圾回收), 如果 gc 以后, 内存还是不够, 就会出现内存溢出

结果: 严重的情况, 整个 java 进程挂掉了

解决方案:

  1. 优化代码 (空间复杂度): 复用变量等
  2. java进程启动时, 加大对应内存区域的空间
  3. 如果系统内存不足以满足第2个条件, 还可以加大系统内存

1.2 内存泄漏

内存中, 随着进程运行时间越来越长, 存放的无用的数据 (变量/常量值, 对象, 类型) 越来越多, 可用内存空间越来越少

在这里插入图片描述

解决:

  1. 程序代码上优化: 如设置超时时间, 定期清理长期不用的数据 (可以使用JVM 检测工具)
  2. 临时方案: 有时候有些老旧的大型项目, 不好优化 (即使使用内存泄漏检测工具, 也不好定位)
    隔一定时间, 重启java 进程 或者 加内存

内存泄漏, 随着使用时间越来越长, 最终一定会OOM
但OOM不是一定有内存泄漏引起

2. 垃圾回收

GC, java 进程在启动后会创建垃圾回收线程, 来对内存中的无用对象进行回收

什么是垃圾?
无用的对象 (堆), 常量 (常量池), 类型 (方法区的类信息)

关于垃圾回收
java进程启动—>创建gc线程

  1. 基于垃圾回收算法来执行回收工作
  2. 不同的垃圾回收器, 使用的算法不同
  3. 回收方法区, 堆中的垃圾

什么时候垃圾回收?
创建对象/ 常量/ 类加载, 先需要在某个内存区域分配内存空间, 如果空间不足, 则执行 gc, 如果 gc 后还不够, 就 OOM

System.gc() : 运行垃圾回收器。
调用gc方法表明,Java虚拟机花费了回收未使用对象的努力,以使其当前占用的内存可以快速重用。 当控件从方法调用返回时,Java虚拟机已经尽力从所有丢弃的对象中回收空间。

电话System.gc()有效地等效于通话:
Runtime.getRuntime().gc()

2.1 如何判断垃圾

2.1.1 引用技术算法

有增加某个对象的引用, 该对象引用计数器 +1, 减少, 计数器 -1
缺点: 无法解决循环引用的问题, 主流 JVM中, 都没有使用这算法

2.1.2 可达性分析算法

可达性分析算法的核心思想为 : 通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。

GC Roots: 线程运行时, 局部变量(引用) 指向的对象

在这里插入图片描述

2.3 回收的内存区域

回收方法区:
1.7 里面叫方法区(Method Area) , 1.8 称为元空间(Metaspace)

gc中, 称为永久代, 属于真实 JVM 内部 gc 实现时, 使用的内存描述
方法区 / 元空间的概念, 不是真实的 JVM实现的依赖, 只是表达了要存放什么样的数据

虽然叫永久代, 但是不意味着对象在这里是永久存活的, 还是可以回收, 只是回收率, 效率比较低

回收堆:
gc 中, 把堆也称为gc堆
在这里插入图片描述

2.4 垃圾回收算法

2.4.1 标记清除算法

老年代的回收算法

分为2个阶段:

  1. 标记: 标记无用对象 (不可达)
  2. 清除: 清除标记的垃圾

缺陷:

  1. 效率不高: 两个阶段的效率都不高
  2. 内存碎片问题: 存在内存碎片时, gc后, 再次创建大对象时 (需要连续的内存空间), 真个内存的可用空间是足够的, 但是连续可用空间不足, 提前触发下一次 gc

2.4.2 复制算法

新生代的回收算法

在这里插入图片描述
优点:

  1. 新生代的对象, 大部分都是朝生夕死 (创建出来以后, 很快就不可达), 复制存活对象, 性能很高 (存活对象很少)

线程调用的方法: 方法中局部变量的方式创建对象
方法栈出栈(方法返回), 堆中对象就是不可达

  1. 没有内存碎片化问题

缺陷:

  1. 内存利用率不高, 50%

优化方案:
提高新生代内存的利用率

2.4.3 标记整理算法

老年代的回收算法 (对象存活率较高时, 使用)

在这里插入图片描述

优点:

  1. 没有内存碎片化问题

2.4.4 分带收集算法

属于一种算法思想, 没有算法实现; 具体来说, 把堆划分为好几块
(新生代: Eden区, S0, S1), 使用复制算法的升级版
(老年代): 使用标记清除算法或标记整理算法

对于GC 堆中,
新生代 gc: (指对用户线程的影响较小), 对象的存活率较低, 回收频率非常高, 效率也很高

老年代 gc: (指对用户线程的影响较大), 回收速度要比新生代gc满10倍以上

以上是关于JVM垃圾处理机制的主要内容,如果未能解决你的问题,请参考以下文章

JVM垃圾处理机制

JVM垃圾处理机制

JVM垃圾处理机制

JVM垃圾处理机制

jvm的垃圾回收机制

JVM垃圾收集机制