垃圾回收与算法

前边讲到 JVM 运行时内存的地方,关于新生代、老年代中 GC 垃圾回收以及垃圾回收算法,不知是否有点懵懵的,这篇一起了解一下垃圾回收以及垃圾回收算法。

一、垃圾回收需要完成的三件事

  1. 哪些内存需要回收?——垃圾对象(如何判定对象为垃圾对象)
  2. 如何回收?——垃圾回收算法
  3. 何时回收?

1. 哪些内存需要回收?

判定为 "死" 对象,或者无用对象时即视为可回收内存。

如何判定为垃圾对象,在这有两个方法。

1.1 引用计数算法

在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。
简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。

这种方法的效率非常的高,但是却有一个很大的缺点,无法解决相互引用的对象,导致进入计数的死循环,致使引用计数算法无法通知 GC 收集器回收他们。

因为这种弊端,在主流的 Java 虚拟机里面没有选用计数算法来管理内存的。

1.2 可达性分析算法

为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。

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


2. 如何回收?——垃圾回收算法

2.1 标记-清除算法(几乎都不用)

该算法为最基础的垃圾收集算法,如同名称一样,该算法分为 "标记" 和 "清除" 两个阶段。

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

从图中我们就可以发现,该算法最大的问题是内存碎片化严重,空间碎片太多,内存不足时,很容易触发下一次 GC。

2.2 复制算法(新生代使用)

为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块用完了,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次性清理掉,每次都对整个半区进行内存回收,不需要考虑碎片问题,如图:

这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying 算法的效率会大大降低。

补充:现在商业虚拟机都是采用复制算法来回收新生代,对象在创建时,虚拟机将内存划分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和一块 Survivor , 当回收时,将 eden 和 Survivor 中还存活着的对象一次性的复制到另一块 Survivor 空间上,然后清理掉 eden 和刚才用过的 Survivor 空间。

hotspot 默认 Eden 和 Survivor 比例为:8:1,也就是只有 10% 的空间被浪费。

2.3、标记整理算法(老年代使用)

标记整理,跟 标记-清除 算法中的标记过程是一样的,只是后续不是直接对可回收对象进行清理,而是让所有存活的对象向一端移动,然后直接清理掉端界边界以外的内存。如图:

2.4、分代收集算法

分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将 GC 堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。

老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。


3. 何时回收?

何时回收之前,先了解一下几种 GC。

  • Minor GC:该 GC 会清理年轻代的内存,GC 时会触发 "全世界的暂停"
  • Major GC/Full GC:清理老年代。

如下是几种 GC 的触发场景:

  1. 执行 system.gc() 的时候
  2. 老年代空间不足,GC 之后,空间不足会触发 outofmemoryError
  3. 永久代空间不足,GC 之后,空间不足会触发 java.outofMemory PerGen Space
  4. Minor GC之后 Survior放不下,放入老年代,老年代也放不下,触发FullGC,或者新生代有对象放入老年代,老年代放不下,触发FullGC
  5. 新生代晋升为老年代时候,老年代剩余空间低于新生代晋升为老年代的速率,会触发老年代回收
  6. new 一个大对象,新生代放不下,直接到老年代,空间不够,触发FullGC

二、重新疏导 JVM GC 过程。

Java 堆是垃圾收集器管理的主要区域,该区域又分为新生代、老年代,而新生代又分为一个 Eden 区和两个 Survivor 区,关于对象的创建,优先在 Eden 区中分配,当 Eden 区没有足够空间时,虚拟机将触发一次 Minor GC,由于大多数对象都是朝生夕灭,所以 Minor GC 非常频繁,速度也非常快。

Full GC,发生在老年代的 GC,当老年代没有足够的空间时即发生 Full GC,发生 Full GC 一般都会有一次 Minor GC,我们在这将 Full GC 等价于 Major GC,也许会有疑问,Full GC 跟 Major GC 到底有什么区别呀,由于许多 Major GC 是由 Full GC 触发的,所以很多情况下将这两种 GC 分离是不太可能的,在这就不继续填坑了,感兴趣的小伙伴可以自行搜索了解。

三、最后总结

首先要清楚垃圾回收要干的三件事,哪些需要回收、如何回收以及何时回收。
通过 "引用计数算法"(不推荐) 或 "可达性分析算法" 来判定需要回收的对象,知道了需要哪些是需要回收的对象,再通过垃圾回收算法(复制、标记清除、标记整理、分代收集)实现垃圾回收。

补一张图:

如果文章有错的地方欢迎指正,大家互相留言交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:niceyoo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/414543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 起调手机QQ,联系客服

1、起调QQ聊天 public void toQQ(){// 跳转之前,可以先判断手机是否安装QQif (isQQClientAvailable(this)) {// 跳转到客服的QQString url "mqqwpa://im/chat?chat_typewpa&uin200870769";Intent intent2 new Intent(Intent.ACTION_VIEW, Uri.p…

jeecg中excel导出字段判空处理

jeecg中excel导出字段判空处理 我们清楚,jeecg 导出 excel 采用的是 easypoi,不知道是否遇到过这种情况: 我们以一个实体属性为例: Excel(name"问题分类",dicCode"xx")private java.lang.String mwoQuestion…

Android LinearLayout加载Fragment

为LinearLayout添加Fragment效果 1、创建Fragment public class Fragment1 extends Fragment {public static Fragment1 getInstance(Bundle bundle) {Fragment1 fg new Fragment1();fg.setArguments(bundle);return fg;}protected View contentView;Overridepublic View onC…

工作247:uniapp--实战--flex布局--商户星级

<template><view ><view v-for"(item,index) in 5"><view style"display: flex;padding: 24rpx 0 0 30rpx;"><text style"font-size: 30rpx;color: #333333;">001-祝菲</text><text style"margin-…

微信小程序开发实战基础一、页面跳转,底部导航栏,分享,加载图片标签,列表

1、页面跳转 wx.navigateTo({ url: "../four/four" })——可返回 wx.redirectTo({ url: "../four/four" })——不可返回 <view> <navigator url"../four/four" hover-class"changestyle">页面跳转&#xff0c;可以返回…

Java面向对象---重写(Override)与重载(Overload)

一、重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变&#xff0c;核心重写&#xff01; 重写的好处在于子类可以根据需要&#xff0c;定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。 重写方法…

Java集合List、Set、Map

集合是 java 基础中非常重要的一部分&#xff0c;同样也是 Java 面试中很重要的一个知识点。所以&#xff0c;给王小整理了这篇关于集合的文章。 1、接口继承关系以及实现 集合类存放于 Java.util 包中&#xff0c;主要有 3 种&#xff1a;set、list 和 map。 Collection&…

SpringBoot项目修改html后不即时编译

SpringBoot项目修改html后不即时编译 springboot templates 下的 html 修改后无法达到即时编译的效果&#xff0c;搜索资料后记录笔记。原文地址&#xff1a;https://www.cnblogs.com/jiangbei/p/8439394.html 1、pom中引入依赖 <dependency> <groupId>org.spr…

工作250:uniapp--实战--flex布局--星级评分

<template><view ><view v-for"(item,index) in 5"><view style"display: flex;padding: 24rpx 0 0 30rpx;"><text style"font-size: 30rpx;color: #333333;">001-祝菲</text><text style"margin-…

Java异常分类及处理

一、概念 如果某个方法不能按照正常的途径完成任务&#xff0c;就可以通过另一种路径退出方法。在这种情况下 会抛出一个封装了错误信息的对象。此时&#xff0c;这个方法会立刻退出同时不返回任何值。另外&#xff0c;调用 这个方法的其他代码也无法继续执行&#xff0c;异常…

工作252:uniapp--实战--uview---tabber

第一步 <u-tabbar v-model"current" :list"list" :current"current" :mid-button"true" change"change"></u-tabbar> 第二步 export default {data() {return {list: [{iconPath: "home",selectedI…

Java反射机制概念及应用场景

Java反射机制概念及应用场景 Java的反射机制相信大家在平时的业务开发过程中应该很少使用到&#xff0c;但是在一些基础框架的搭建上应用非常广泛&#xff0c;今天简单的总结学习一下。 1. 什么是反射机制&#xff1f; Java反射机制是在运行状态中&#xff0c;对于任意一个类&…

Android 支付宝登录

实现效果&#xff1a; 截取authCode的方法 int startCity info.indexOf("authCode{") "authCode{".length(); int endCity info.indexOf("}", startCity); String code info.substring(startCity, endCity);//获取市Log.i("lgqshouqau…

python打造社工脚本

0x00前言&#xff1a; 大家都知道图片是有Exif信息的。里面包含着 你的GPS信息。还有拍摄时间等等的敏感信息。 0x01准备: exifread requests 0x02思路: 读取图片的Exif信息。 如果有GPS信息就将其扔到脚本的ip定位功能 0x03代码&#xff1a; import optparse from PIL import …

Android 中英文语言切换

非常简便&#xff0c;只需替换一个文件再添加上去即可 strings和-zh文件链接&#xff1a;https://download.csdn.net/download/meixi_android/11367095 1、首先替换原strings文件 2、复制添加-zh文件 3、修改添加各个name对应中英文即可 4、切换手机设置里面语言选项即可切换A…