IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JVM垃圾收集回收 -> 正文阅读

[Java知识库]JVM垃圾收集回收

垃圾收集是编程语言在设计时需要考虑的问题,垃圾收集最早起源于LISP语言,有很多语言都是支持垃圾收集的,如Python、Go、PHP、Js、Lua、Java、C#、D等, 不支持垃圾回收的语言有c/c++等。

?

所以垃圾收集不是Java一个要面对的问题,这是个通用的技术点,这里我们只讨论Java相关的垃圾收集。

一、JVM需要回收的区域

JVM规范定义了运行时数据区域分为5个部分,分别为堆、方法区、虚拟机栈、本地方法栈、程序计数器。其中虚拟机栈、本地方法栈、程序计数器都是伴随线程生命周期关联,随线程产生和消失,这3个区域的的回收直接跟随线程即可。而堆和方法区不一样,里面的内容是动态变化的,由程序的具体内容决定,所以这两个区域的回收需要动态执行。垃圾回收之前,需要将能够回收的垃圾找出来,就需要有算法来计算哪些对象是存活的,哪些是垃圾。

二、垃圾识别算法

垃圾收集之前必须要知道哪些对象是垃圾,才能进行后续的收集工作。当前使用的较多的垃圾识别算法有2种,分别是引用计数法(reference counting)和可达性分析法(Roots tracing)。

引用计数法

引用计数是GC中早期的策略,在这种算法下,每一个在堆中的对象都有一个计数关联,当一个对象被创建后,每当他的引用被赋值给另一个变量时,计数就会加1,每当引用这个对象的变量生命周期结束后,计数就会减1,这样就能知道有多少地方引用着对象,当引用计数为0时就表明这个对象已经可以被回收了。引用计数法的优势是可以很快的执行,缺点就是如果发生了循环引用,对象就无法被回收,所以想要使用引用计数法,一定要解决循环依赖计数的问题。

可达性分析法

可达性分析算法是根据离散数学图论作为理论基础,该算法将程序中的所有引用关系建模成图,图由GC Root根节点开始,向下建立所有引用关系,形成引用链(reference chain),当所有的图建立完成后,如果发现有对象不在图中,也就是GC Root到这些对象不可达,那么这些对象就是无人引用的对象,也就是需要回收的垃圾。GC Root在对象图之外,是特别定义的起点,不可能被其他对象引用。

在Java中,可以作为gc root的对象有4种:
1、虚拟机栈中引用的对象(栈帧里的本地变量表)
2、方法区中类静态成员引用的对象
3、方法区中常量引用的对象
4、本地方法栈中JNI引用的的对象

三、Java中引用类型

无论是引用计数法还是可达性分析法,都和对象的引用的关系有关,Java根据引用的关系强弱划分了4个层次,分别为
强引用(Strong Reference)
软引用(Soft Reference)
弱引用(Weak Reference)
虚引用(Phantom Reference)
4种,这4种引用强度依次逐渐减弱。这四种引用提供给用户使用,我们通常使用的就是强引用,比如下面的代码就是强应用

A a = new A();

四、方法区的垃圾回收

方法区中需要回收的内容通常是无用的常量和无用的类型,无用的常量可以使用可达性分析算法来回收,对于无用的类的回收则需要满足以下3个条件:
1、该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;
2、加载该类的ClassLoader已经被回收;
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

五、JVM常用的垃圾收集算法

引用计数法

可以直接使用引用计数法来进行垃圾回收,随时监控对象的引用数量,进行回收,但是使用这种算法需要解决循环引用的问题。主流的Java虚拟机没有使用这种算法。

标记清除法(Mark-Sweep)

标记清除算法分为标记和清除2阶段操作,标记阶段直接使用可达性分析算法扫描所有的对象,标记处需要回收的垃圾,清除阶段将标记出的对象清理回收,这种算法简单直接,不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记清除算法直接回收不存活的对象,因此会造成内存碎片。

复制算法(Coping)

为了解决标记清除算法的内存碎片缺陷,复制算法被提出来了,复制算法将可用的内存空间划分为大小相等的2块区域,运行时只会使用其中一块,在触发垃圾回收时,通过可达性分析算法计算出所有存活对象,然后将他们复制到另一块空闲区域,?完成一次回收,复制算法解决了内存碎片的问题,但是他对内存空间的浪费较大,同时如果对象存活较多时,效率会较低。

标记整理算法(Mark-Compact)

?为了解决复制算法的内存利用率低的问题,标记整理算法被提出来了,分为标记和整理2阶段,标记阶段通过可达性分析算法将内存区域所有对象打上标记,区分出存活对象和回收对象,整理阶段将存活对象全部移动到内存的一端,剩下的空间就是可用区域了,他解决了复制算法的内存利用率低的弊端,但是需要付出复制对象的代价。

分代收集算法(generation collection)

分代收集算法是目前绝大多数数Java虚拟机采用的回收算法,分代回收算法的前提是JVM将堆划分为新生代(young generation)和老年代(old generation),默认大小比值为1:2,其中新生代又被分为Eden和Survivor From(s0)和Survivor To(s1),默认大小比例为8:1:1。

新生代主要采用的算法是复制算法(区域划分是8:1:1不是1:1),运行时,新产生的对象放入新生代的Eden区,在合适实际会触发Minor GC(不一定是Eden满了才触发),然后将Eden中存活的对象放入s0,如果s0满了,就将Eden和s0中存活对象复制到s1中,(如果s1空间不够,就将对象存放到老年代去,不要存放到s1了)此时s0就被清空了,然后交换s0和s1地址,如果Eden中又发生Minor GC,就将存活对象复制到s0,如此往复。

老年代主要采用的回收算法是标记整理算法,当老年代内存到达一定值时,触发Major GC,也叫Full GC,老年代里面都是一些存活率较高的对象,使用标记整理算法,内存利用率较高。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 20:35:37  更:2022-03-21 20:38:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:15:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码