当前位置: 首页 > article >正文

深入了解jvm垃圾回收

1、为什么要有GC,哪些内存对象需要回收?

对于一个Java开发者来说,了解过Java内存区域的都知道,Java内存区域分了堆、栈、程序计数器等等。

Java的程序计数器,栈内存 ,他们随线程生,随线程灭,方法结束后内存也就回收了。

一个字符串“abc”已经进入常量池,但是当前系统没有任何一个String对象引用了做“abc”的字面量,那么,如果发生垃圾回收并且有必要时,“abc”就会被系统移出常量池。
常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

当Java虚拟机发现内存资源紧张的时候,就会自动地去清理无用变量所占用的内存空间,为我们的程序提升更高的性能。

2、如何判断对象需要回收?

一般常见的两种回收判断算法:

2.1、 引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1。

任何时刻计数器为0的对象就是不可能再被使用的。
在这里插入图片描述
该方法实现简单,效率高,但是它很难它很难解决对象之间相互循环引用的问题。比如图中的 Object3 和Object4相互引用,引用计数不可能为0,虽然它们已经没有被Root引用了。

所以,大多数jvm判断对象是否存活基本并没有采取该方法。

2.2、可达性分析算法(根搜索算法)

这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)。

当一个对象到GC Roots没有任何引用链相连时(不可达)则证明此对象是不可用的。

要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

在这里插入图片描述
被认为GC Roots的有以下几种:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性、常量引用的对象
  • Native方法引用的对象

3、如何回收(垃圾收集算法)?

随着Java虚拟机的发展,jvm衍生出了很多种垃圾回收算法。

1、标记-清除(Mark-Sweep)算法

最基础的垃圾回收算法,分为两个阶段,标记和清除。

标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。

在这里插入图片描述
从图中我们就可以发现,该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。

2、复制算法(copying )

为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为相等大小的两块。

每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉,如图:
在这里插入图片描述
这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying 算法的效率会大大降低。

3、标记-整理(Mark-Compact)算法

结合了以上两个算法,为了避免缺陷而提出。标记阶段和 标记-清除(Mark-Sweep)算法 相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除两端边界外的对象。
在这里插入图片描述
直接清除边界的对象也不好,如果边界是老年代,每一次都被清除就很不合理。

4、分代收集算法

分代收集法是目前虚拟机(包括HotSpot VM)收集器都是采用该方法。
在这里插入图片描述
对象将根据存活的时间被分为:新生代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区),然后进行分代回收,分算法回收。

新生代:对象被创建时,内存的分配首先发生在新生代(准确地说是Eden区,大对象(大于Eden空间)可以直接 被创建在年老代)

新生代又划分为 Eden 区 + Survivor区 (Survivor区又分 from 和 to 区),大小分别占 80%,10%,10%。

Eden区是连续的内存空间,因此在其上分配内存极快。

老年代:老年代存储的对象比新生代多,而且大对象也多。老年代用的算法是标记-整理算法。

永久代(方法区):1.8就没有了,只有元空间。常见的就是常量池、类信息等等。

分代收集算法的GC过程:

(1)在年轻代中,Eden区提供堆内存如果满了,Eden进行MinorGC,将存活的对象→from ,Eden区清空;

(2)Eden区再次满, Eden 区和 from 区同时进行 Minor GC,把存活对象放入 to 区,Eden和from 同时清空;

如果在to区中的对象仍然存活,则把对象标志 +1。

(3)重复(2)的操作, 某些对象在反复 Survive 15 次后,或者Eden+from 的存活对象 > to ,这些对象就只能放到老年代了,如果老年代放不下了,就进行Full GC);

(4)当 Old 区也被填满时,进行 Full GC,对 Old 区进行垃圾回收。

可以通过参数 SurvivorRatio 手动配置 Eden 区和单个 Survivor 区的比例,默认为 8。可以通过参数–XX:SurvivorRatio 来设定,即将堆内存中年轻代划分为8:1:1

4、垃圾回收器

垃圾回收器是虚拟机不断发展产生的,不同的垃圾回收器使用不同的垃圾回收算法(下面讲到)

以HotSpot VM来说,垃圾回收器大致分为七种类型:

  • 串行:Serial New收集器

  • 串行:Serial Old收集器

  • 串行:ParNew收集器

  • 并行:Parallel收集器

  • 并行:Parallel Old 收集器

  • 并发标记扫描CMS收集器

  • G1收集器

  • 在这里插入图片描述

注:串行、并行 其它工作线程要暂停,并发不会。

5.JVM常见参数

设置合理的jvm参数对Java程序有至关重要的作用。

基本设置:
-Xms300m 起始内存(堆大小)设置为300m
-Xmx 最大内存
-Xmn 新生代内存
-Xss 栈大小。就是创建线程后,分配给每一个线程的内存大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。


http://www.kler.cn/a/8022.html

相关文章:

  • GitLab 服务变更提醒:中国大陆、澳门和香港用户停止提供服务(GitLab 服务停止)
  • FFmpeg来从HTTP拉取流并实时推流到RTMP服务器
  • Type-C单口便携显示器LDR6021
  • 命令手动更新 Navigator
  • React引入Echart水球图
  • 大模型-使用Ollama+Dify在本地搭建一个专属于自己的聊天助手与知识库
  • 关于函数torch.topk用法的思考
  • axios 导出excel表格 文件流格式
  • Alibaba开源的Java诊断工具Arthas-实战
  • [ 应急响应基础篇 ] 解决远程登录权限不足的问题(后门账号添加远程桌面权限)
  • 华为OD机试-组合出合法最小数-2022Q4 A卷-Py/Java/JS
  • 深入浅出Kafka
  • Linux账号管理(用户{创建删除修改}用户组{创建删除修改}一般用户命令{id,finger,chfn,chsh})
  • 【JavaWeb】8—过滤器
  • 【架构师从零进阶】Java基础 练气期 Day1
  • 旅游心得Traveling Experience
  • 从零开始:如何集成美颜SDK到你的应用中
  • Redis常用命令以及如何在Java中操作Redis
  • springcloud——并发请求处理方案
  • 软件测试面试复盘:技术面没有难倒我,hr面被虐的体无完肤
  • 笔记-常见的动态内存错误
  • 收割offer疯狂涨了5K,自动化测试面试题整理大全,你能答上多少?
  • js设计模式——组合模式
  • RBF-UKF径向基神经网络结合无迹卡尔曼滤波估计锂离子电池SOC(附MATLAB代码)
  • 在cmd命令窗口安装Python模块
  • 入门力扣自学笔记257 C++ (题目编号:1041)