GC 垃圾回收机制的初步认知

GC 垃圾回收机制

前提:

在介绍垃圾回收机制之前,我们应该了解一下我们为什么要进行垃圾回收。再往前刨一刨,我们就应该了解一下什么是内存。


一、内存简介

RAM(random access memory)随机存取存储器。一般Java在内存分配时会涉及到以下区域:

1.寄存器(Registers):速度最快的存储场所,因为寄存器位于处理器内部,我们在程序中无法控制

2.栈(Stack):存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中

3.堆(Heap):堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器(GC)来管理。

4.静态域(static field): 静态存储区域就是指在固定的位置存放应用程序运行时一直存在的数据,Java在内存中专门划分了一个静态存储区域来管理一些特殊的数据变量如静态的数据变量

5.常量池(constant pool):虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。

6.非RAM存储:硬盘等永久存储空间

在这里插入图片描述

Java 内存图

二、内存泄露

1.内存泄漏是指
  某一段内存在程序里功能上已经不需要了,但是垃圾回收机制回收内存时检测那段内存还是被需要的,不能被回收,这种在程序中在没有使用的但是又不能被回收的内存就是被泄漏的内存

2.产生的影响
  内存泄漏会导致一些内存没法被正常利用,话句话就是可以使用内存变少了,这样轻则增加垃圾回收机制运行频率,重则内存溢出(当系统需要分配一段内存,但是现有内存在垃圾回收运行后任然不足时,就会内存溢出)。

3.避免内存泄漏的做法
  在写程序时已经确定不需要的引用型变量,就置空;虽然即使内存没泄露,也有可能出现内存溢出,这时的内存溢出就是有别的问题导致的。


正文

一、垃圾回收的定义

1.垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

2.判断一段内存是否是垃圾,是否可回收的条件,这个条件是通过检查这段内存是否存在引用和被引用关系,不存在这关系时,就认为可回收,若还存在引用或被引用关系,就认为不可回收。


二、那些内存需要回收?

1、 引用计数算法:判断对象的引用数量
(1)当一个对象被创建时,且将该对象实例分配给一个引用变量,该对象实例的引用计数设置为 1。
(2)当任何其它变量被赋值为这个对象的引用时,对象实例的引用计数加 1(a = b,则b引用的对象实例的计数器加 1);但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数减 1。
(3)特别地,当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器均减 1。
(4)任何引用计数为0的对象实例可以被当作垃圾收集。
注:若两个对象相互引用,即引用计数永远不可能为 0,那么这两个对象就永远不能被回收,就会造成内存的浪费。

2、 可达性分析算法:判断对象的引用链是否可达
  在可达性分析算法中,程序把所有的引用关系看作一张图,通过一系列的名为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)。
  当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的,故此对象可以释放。
  在Java中,可作为 GC Root 的对象包括以下几种:
   a、虚拟机栈(栈帧中的局部变量表)中引用的对象;
   b、方法区中类静态属性引用的对象;
   c、方法区中常量引用的对象;
   d、本地方法栈中Native方法引用的对象;


三、如何回收?

三种经典垃圾回收算法(标记清除算法、复制算法、标记整理算法)
1、标记清除算法
  标记-清除算法分为标记和清除两个阶段。该算法首先从根集合进行扫描,对存活的对象对象标记,标记完毕后,再扫描整个空间中未被标记的对象并进行回收。

2、复制算法
  复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  适用场景:新生代。

3、标记整理算法
  标记整理算法的标记过程类似标记清除算法,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
  适用场景:老年代

4.分代收集算法
 (1)分代收集算法是基于这样一个事实: 不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。
 (2)当代商用虚拟机使用的都是分代收集算法:新生代对象存活率低,就采用复制算法;老年代存活率高,就用标记清除算法或者标记整理算法。
 (3)Java堆内存一般可以分为新生代、老年代和永久代三个模块


七种垃圾收集器

1.Serial收集器 (复制算法)
  新生代单线程收集器,标记和清理都是单线程,优点是简单高效;

2.Serial Old收集器 (标记-整理算法)
 老年代单线程收集器,Serial收集器的老年代版本;

3.ParNew收集器 (复制算法)
 新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;

4.Parallel Scavenge收集器 (复制算法)
 新生代并行收集器, 追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;

5.Parallel Old收集器 (标记-整理算法)
 老年代并行收集器, 吞吐量优先,Parallel Scavenge收集器的老年代版本;

6.CMS(Concurrent Mark Sweep)收集器 (标记-清除算法)
 老年代并行收集器, 以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。

7.G1(Garbage First)收集器 (标记-整理算法)
 Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。
 此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代


  未完待续************************************************


  写GC之前的思路:内存 -> 内存泄漏 -> 内存优化 -> 垃圾回收 -> ※ 垃圾回收机制。查阅资料之后,有了一定的修改。第一次学习GC,还不太完善,之后会进行进一步的更新。


借鉴的资源
1.内存优化:https://www.jianshu.com/p/2e561aee037a
2.内存图:https://www.jianshu.com/p/7b2a01e1cf41
3.图解Java 垃圾回收机制:https://juejin.im/entry/6844903666156044296


本文涉及到的所有图例均由笔者整理所得,其中部分由笔者亲自绘制,部分借鉴于互联网并在其基础上修改而成。若涉及版权,请留言评论或直接私聊笔者。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xie_bro777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值