java 全局变量 内存不回收_Java的内存 - 内存回收

这篇承接上一篇 《Java的内存 - 内存模型》,分析内存回收相关的知识点。 垃圾回收包含两个步骤,①标记哪些内存是垃圾 ②回收内存。下面分别说这两个步骤有哪些算法:
1. 垃圾标记
1.1 引用计数算法
没有哪一种 JVM 是使用「引用计数」作为垃圾回收算法的,但这种算法又很经典,所以介绍一下。
工作方式: 堆中每一个对象都有一个引用计数器。创建并初始化赋值后,引用计数置为1,每多一次引用,引用计数+1,每有一个引用失效(出作用域 或者 被设置为其他值)时,引用计数-1。引用计数 == 0 的对象可以被回收。
优点: 判定对象是否需要回收的效率高,不需要额外的线程做 GC 的工作,也不会暂停应用。
缺点: 无法检测循环依赖。由于需要实时计数,增加了程序执行时的开销。
应用实例: Object-C 的 ARC 模式。
1.2 根搜索算法
根搜索算法是 Java 虚拟机主流的找垃圾算法。
首先要知道根集和finalize()相关的东西:
根集: 根集是肯定不需要回收的对象的引用。它包含: 1. Java栈 和 Native栈 的本地变量表中引用的对象; 2. 方法区中的常量和静态变量引用的对象; 3. 活跃的线程对象等。
关于 finalize() 方法: finalize() 方法最多只会被 垃圾收集器 执行一次(不包括开发者主动调用)。已经被垃圾收集器执行过一次后,不会再执行第二次。如果一个类没有重写 finalize() 方法,垃圾回收器不会执行其对象的 finalize() 方法。
根搜索算法会有两次标记,第一次标记将需要执行 finalize() 的对象放入 F-Queue 中,等待执行 finalize() 方法;第二次再判断执行完 finalize() 的对象是否依然不可达,并最终确定哪些对象是垃圾。 finalize() 方法是在一个低优先级的线程中执行的。
工作步骤如下:
第一步:获取不可达对象 1. 暂停整个应用(Stop The World); 2. 生成根集(GC Roots); 3. 从根集出发,找出根集中的对象引用的其他对象,并依次沿引用方向遍历,生成引用链; 4. 根据引用链获取所有不可达的对象;

第二步:垃圾的自我救赎 1. 判断这些不可达对象是否需要执行 finalize() 方法; 2. 如果不需要,直接标记为可回收对象,跳过后续步骤;如果需要,将对象加入到 F-Queue 中,等待执行 finalize() 方法; 3. 如果在 finalize() 方法中,其他对象又持有了该对象,那么该对象又变为可达对象了。
第三步:再次获取不可达对象 1. F-Queue队列执行完后,再次判断执行完 finalize() 方法的这些对象是否可达; 2. 如果仍然不可达,标记为可回收对象。
2.2 垃圾收集
关于垃圾回收,参考 Oracle 官网 《HotSpot 虚拟机内存管理白皮书》。
垃圾回收确保回收的对象必然是不可达对象,但是不确保所有的不可达对象都会被回收。
垃圾收集算法主要有3种: 标记清除算法(Mark-Sweep) 、标记压缩算法(Mark-Sweep-Compact)、复制算法(Copying)。在这3种的基础上派生出其它算法: 1. 分代回收:考虑算法和内存分配的特点,对堆上不同的分代使用不同的回收算法; 2. 并行回收(Parallel)和 串行回收(Serial): 考虑在内存回收时,是一个线程在回收,还是多个线程同时回收; 3. 并发回收 和 Stop-The-World:考虑在内存回收时,是否一边执行应用一边回收,还是完全暂停整个应用;
以下是这些算法的具体信息:
2.2.1 标记清除算法
工作方式: 1. 内部维护了一个空闲内存表,用来记录可分配内存的地址和大小; 2. 工作时,先将标记为可释放的对象的内存释放,然后在空闲内存表中更新可分配内存信息。

优点: 速度快。快的原因,相比后面的标记整理算法,是不需要移动内存。
缺点: 1. 会产生大量的内存碎片; 2. 维护一个空闲列表有一定的额外开销; 3. 分配新内存时,需要遍历空闲列表找到合适的内存块。
2.2.2 标记整理算法
工作方式: 1. 将所有活跃的对象,依次移动到内存的一端; 2. 移动完毕后,清理边界之外的内存。

优点: 1. 不会产生内存碎片; 2. 只需要记录内存末尾的指针,新内存分配时可以立即分配;
缺点: 1. 由于需要移动内存,暂停应用的时间会延长。
2.2.3 复制算法
工作方式: 1. 将堆内存分为两块相同的区域; 2. 内存分配时,只在其中一块内存分配; 3. 当内存不足以分配时,将所有活跃的对象依次复制到另一块区域; 4. 一次性清理掉旧的内存区域。

优点: 1. 标记和复制可以同时进行; 2. 效率高,清理内存时是对一整块内存进行操作; 3. 不会产生内存碎片。
缺点: 1. 可分配的堆内存减为一半了; 1. 由于需要移动内存,暂停应用的时间会延长。
特点: 该算法的耗时,只跟活跃对象的数量有关,和这个算法管理的堆空间总大小无关。
2.2.3 分代回收
由于不同对象的生命周期是不一样的,因此可以对不同生命周期的对象采取不同的收集方式,以提高回收效率。
不分区有什么缺点: 如果不分区,GC是对整个堆区进行可达性分析、内存移动等,回收会很耗时。
如何划分内存区域: 由于大部分对象的生命周期很短,只有少部分对象会存活较长时间。所以基于它们的生命周期分代是个合适的选择。HotSpot 等虚拟机都把堆区分为 年轻代 和 老年代。
分代是如何减少可达性分析的: 对年轻代做可达性分析时,如果还要遍历老年代,那就没有减少可达性分析的时间。 但是。如果不遍历其它分代,如何知道一个年轻代的对象是否被老年代持有呢?这就产生了跨代引用的问题。
为了解决问题,引入了「跨代引用是 GC Root」的解决办法:如果老年代的 Young 对象,引用了年轻代的 Old 对象,在对年轻代进行可达性分析时,Young 对象算作 GC Root。这样就不用遍历其它分代了。 分代回收算法需要有一个表,用来记录所有的跨代引用,很耗内存。HotSpot 使用 CardTable 记录老年代对年轻代的引用。把老年代按照 4KB 的大小分块,每一块对应在 CardTable 中都是1 bit。当值为1时,表示这4KB 的内存中有对年轻代的引用,需要加入到 GC Roots 中。

这种解决办法也会有问题:如果A对象没有被其它对象引用,实际上A、B都应该被回收,但却把B当作GC Root了。也就是部分不可达对象没有被回收。
如何选择合适的算法: 1. 对于年轻代的对象,它们数量多、生命周期短,且大部分对象都是要回收的,所以需要速度更快的垃圾回收算法。Copying 算法的耗时,只跟堆内活跃对象的数量有关,跟堆的大小无关,所以特别适合用于年轻代的回收。 2. 对于老年代的对象,他们占用内存大,不能使用复制算法,并且需要避免内存碎片,所以使用 标记整理算法。
在回收年轻代时,可达性分析只分析年轻代。在回收老年代时,是对整个堆区做可达性分析。
相关文章:

题目1000:计算a+b
题目描述:求整数a,b的和。 输入:测试案例有多行,每行为a,b的值。 输出:输出多行,对应ab的结果。 样例输入:1 2 4 5 6 9 样例输出:3 9 15 #include<iostream> using…

Mac下chrome的webapp hostadmin 快速切换host
首先是安装 app ,https://chrome.google.com/webstore/detail/hostadmin-app/mfoaclfeiefiehgaojbmncmefhdnikeg Chrome把扩展的NPAPI 禁用了,所以做成APP没以前方便了,但是有总比没有好。 安装之后发现mac下选择host文件没法选,因…

PX4如何开启本地在环仿真?如何将仿真地点定位为本地位置?你进来就对了!
视频预览:3架无人机在环仿真 3架仿真jmavsim本地坐标启动教程 1.首先执行仿真命令 n414414:~/001/Firmware$ make px4_sitl_default jmavsim出现左边界面就说明该仿真是可以进行仿真的!由于我在自己写的代码里面启动,所以出现右边提示&…

Blender从头到尾创建低多边形角色学习教程 Low Poly Characters – Blender Bitesize Course
从头到尾创建低多边形角色。 你会学到: Blender界面的基础。 基本建模技术。 如何遵循字符引用? 如何创造和塑造自己的角色(不同风格、发型和服装)。 纹理字符。 索具和动画介绍(用于你的游戏引擎或动画)。 调整您下载的资产包角色,以创建新的不同角色。…

20145101《Java程序设计》第4周学习总结
20145101《Java程序设计》第4周学习总结 教材学习内容总结 第六章 继承与多态 继承:避免多个类间重复定义共同行为。把相同代码提升为父类 运用extends关键字的子类会继承扩充父类行为 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中&#…

反编译使用yield关键字的方法
我认为这是一个真命题:“没有用.NET Reflector反编译并阅读过代码的程序员不是专业的.NET程序员”。.NET Reflector强大的地方就在于可以把IL代码反编译成可读性颇高的高级语言代码,并且能够支持相当多的“模式”,根据这些模式它可以在一定程…

Android studio 启动自学模式
今天在网上看到了编译Android的软件Android studio,出于对Android的学习兴趣,我打算开始新一轮的Android的学习。今天就是在网上,以及图书馆里查找了有关Android studio的书籍,但是由于Android是在13年才开始发布的原因吧&#x…

AutoCAD 2D与3D大师班学习教程 AutoCAD 2D and 3D Masterclass
用实例和解决问题的方法完成从基础到专业的AutoCAD课程。 你会学到什么 AutoCAD课程包含创建计划和模型的命令和不同方法的详细使用。 本课程包括对AutoCAD中使用的所有命令和工具的详细解释。 课程内容是按时间顺序设计的,以了解承担项目的实际方法。 本课程包含两…

威纶通宏开机后使用初始化宏指令_【操作系统】我们按下电脑开机键的背后发生了什么?...
作者:CVNot链接:https://juejin.im/post/5e8844996fb9a03c6675b9d6操作系统是什么?操作系统是用来管理计算机硬件的软件,狭义上实现该定义的为操作系统内核;而更加宽泛的操作系统概念为根据内核对外提供了一些OS服务&a…

Linux常用压缩与解压缩命令
.tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)———————————————.gz解压1:gunzip FileName.gz解压2:gzip -d…

【Kubernetes】如何使用Kubeadm部署K8S集群
一 . 准备机器 本次环境采用华为云ECS弹性云服务器部署(也可以使用VMware) vm01(2V4G): Ubuntu_18.04作为K8S master节点 vm02(1V1G): Ubuntu_18.04作为K8S node节点 备注: 以下所有…

解决ORA-28000: the account is locked
在oracle中,连续十次尝试登陆不成功,那么此账户将会被锁定(lock)。当使用被锁定的账户登录时,系统会报错:ORA-28000: the account is locked。查询FAILED_LOGIN_ATTEMPTS参数默认值,这个参数限制…
Android sudio Day01-1
今天我开始学习Android studio的第二天,主题是Android studio的安装。 之前的学校学习都是使用Android开发者工具(Android development tools,ADT),而ADT作为一个Android开发工具,它是通过内置于Eclipse的…

学习用C#在Unity中创建一个2D Metroidvania游戏
学习用C#在Unity中创建一个2D Metroidvania游戏 你会学到: 构建2D Unity游戏 用C#编程 玩家统计,水平提升,米尔和远程攻击 敌方人工智能系统 制定级别和级别选择 Learn To Create A 2D Metroidvania Game in Unity With C# MP4 |视频:h264,…

3.27课·········悬浮动态分层导航与隐藏导航
例1:分层导航 <title>分层导航</title> <script src"../JavaScript/jquery-1.4.2.min.js">//引用外部JS代码 </script> <style> #apDiv1 {position: fixed;left: auto;top: auto;bottom: auto;width: 237px;height: auto;z-index: 2;m…

.sh是什么语言_shell的重生历史:从sh到bash
shell 门派之争Linux 中的 shell 有很多类型,其中最常用的几种是:Bourne shell (sh)、C shell (csh) 和 Korn shell (ksh),它们各有优缺点,用户则萝卜青菜,各有所爱。Bourne shell 出师不利Bash:Bourne aga…

【Docker】容器的几种网络模式
当你使用Docker时,你会发现需要了解很多关于网络的知识。Docker作为目前最火的轻量级容器引擎,因此,我们有必要深入了解Docker的网络知识,以满足更高的网络需求。本文介绍了Docker的4种网络模式。 1、首先我们先简单描述一下容器…

微信推送模板消息的PHP代码整理
本文为本人原创,未经许可,不可转载。 博主长期从事微信开发,微信开发相关问题和业务请联系qq 2580234897 最近做过一个需要推送消息的系统,就研究了一下微信的模板消息的推送。由于认证过的微信号,就用测试号做的&…
Android studio Day01-23
AndroidDay01-2(Android studio安装) 步骤如下: (1)下载Android studio下载地址:www.developer.android.com./sdk/installing/studio.html (2)双击安装,建议在studio安…

Unity 3D学习视觉脚本无需编码即可创建高级游戏
在本课程中,您将学习如何在Unity中使用可视化脚本(以前称为Bolt)以及如何在不编写一行代码的情况下创建自己的高级游戏所需的一切。本课程将教你如何掌握可视化脚本,即使你以前没有任何关于unity或编程的经验。 课程获取:Unity 3D学习视觉脚…

树莓派siri homekit_利用树莓派Zero自制一款Homekit摄像头,看上去挺酷,手痒了吗?...
虽然最近相继有多款兼容homekit商用摄像头上市,如果您也和小编一样,喜欢动手,那么DIY一款Homekit摄像头,然后自己3D打印个外壳支架,是不是很酷?HKCam项目Home 4开发者Matthias提供了一个开源项目࿰…

如何释放电脑被限制的20%网速?
很多朋友不管是看电影还是玩游戏,总觉得自己的网速慢,这跟自己所办网络的带宽有一定关系,但我们也要知道,我们的电脑在买来时,默认是限制了20%网速的,如何释放这20%的网速,提高用户体验呢&#…

【Docker】registry部署docker私有镜像仓库
Docker Hub作为Docker默认官方公共镜像仓库,但是如果我们不想使用怎么办,第一我们可以替换默认镜像仓库为我们国内的一些镜像仓库,第二就是如我们自己搭建一个自己的私有镜像仓库,官方也提供docker registry镜像,使得搭…

JAVA 面向对象
1;什么叫面向对象:1;面向对象和面向过程是一种思想2;面向过程:强调的是功能行为3;面向对象:将功能进行封装,强调具备了功能的对象2;面向对象的特征:1…
Android studio Day02-1
AndroidDay02-1(project) 新建一个project,并选择一个自己project的存贮的位置 Android studio 2.3.1默认的最小的API为15 第一次使用并建立自己的project,软件进行相应的sdk其他的组建的安装 点击next进入下一个界面,…

Unity Pro builder创建模块化仓库建筑学习教程
Unity内部的专业3D编辑工作室 你会学到: 直接在Unity内部学习3D建模 使用专业构建器的专业方法 为您的游戏创建模块化资产 了解如何为您的三维模型设置纹理 三维资产的模块化布局 专业后期制作和轻烤 Unity Pro Builder Warehouse MP4 |视频:h264,1280720 |音频:AA…

C++拾遗(五)语句相关
前缀格式与后缀格式 对于表达式:后缀如 i 表达式的值仍是 i,在遇到下一个顺序点后再将 i 加1。前缀 i 表达式的值就是(i1),先计算表达式的值,不需要等待 顺序点。 对于类:前缀函数效…

github里的默认域_GitMAD 一款扫描Github上的敏感信息和数据泄漏工具
GitMAD是一个用于发现Github上的敏感信息和数据泄漏的工具。通过给定关键字或域,GitMAD便会搜索Github上托管的代码,以查找是否存在匹配项。一旦找到了匹配项,GitMAD将克隆存储库并在文件中搜索一系列可配置的正则表达式。然后,Gi…

【Docker】Docker的三大核心组件
镜像(Image)、容器(Container)、仓库(Repository)是我们常说的Docker的三大组件,接下来就让我们一起详细地探索一番吧。 一、镜像(Image) 什么是Docker镜像?…

很高兴开始博客之旅
来到博客园!,开启我的博客之旅,感觉棒棒哒转载于:https://www.cnblogs.com/pbnull/p/4562230.html