引言

Java的内存动态分配和垃圾收集的问题,都交给了JVM来处理。注意,将JVM运行数据区(虚拟机栈【栈帧】,程序计数器,堆内存)粗略的分为栈和堆(所有线程共享),回收的是堆中的对象实例。不是栈中的引用类型。

那么JVM是如何处理的?
从三个问题来分析:
1. 哪些内存需要回收?
2. 什么时候进行回收?
3. 如何回收?

注:现代收集器基本采用分代收集算法,堆分为:新生代和老年代。

1. 哪些内存需要回收?什么时候回收?

1.1 了解下对象的创建:

  1. 通过new 关键字。
  2. JVM遇到new指令,检查是否能在常量池中定位到一个类的符号引用。
  3. 检查是否已被加载,解析,初始化过。
  4. 没有,则执行相应的类加载过程。
  5. 类加载检查通过后,为新生对象分配内存。(类加载后确定对象所需内存大小)
  6. 从Java堆中划分出一块确定的内存。

1.2 若为“死亡”的对象,则需要回收,如何判断对象是否存活?

1.2.1 引用计数算法

  • 给对象添加一个引用计数器
  • 每当有一个地方引用它时,计数器指加1
  • 当引用失效时,计数器指减1
  • 任何时刻计数器为0的对象就是需要回收的
    Java虚拟机没有采用这种方法来管理内存,主要原因是它难以解决对象之间相互循环引用的问题。(python中采用)

1.2.2 可达性分析算法

  • 用一个“GC Roots”的对象(指一系列中的其中一个并非某一种)作为起始点
  • 从该节点向下搜索,搜索走过的路径称为引用链
  • 若一个对象没有与任何引用链相连,即不可达
  • 证明该对象是不可用,死亡
    Java,C#采用此方法。

1.2.3 哪些可作为GC Roots的对象?

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

1.2.4 无论哪种算法都是与“引用”有关,下面分析引用的4种类型,强度依次减弱。

  • 强引用:Java中普遍存在的(如:Object obj = new Object()),只要强引用还在,垃圾收集器永远不会回收掉被引用的对象实例。
  • 软引用:用于有用但非必需的对象。在系统要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。[SoftReference]
  • 弱引用:用于非必需对象。被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。[WeakReference]
  • 虚引用:不影响生存时间,唯一目的就是能在这个对象被收集器回收时收到一个系统通知。[PhantomReference]

1.2.5 详解,真正的”死亡”对象(两次标记后进行回收

事实上,不可达的对象,也并非“非死不可”,这时它们处于“缓刑”阶段,真正死亡至少要经历两次标记过程:

1.2.5.1 第一次标记
  • 对对象进行可达性分析后发现没有与GC Roots相连接的引用链
  • 筛选是否有必要执行finalize()方法[没有覆盖finalize()方法或finalize()方法已经被JVM调用过,视为“无需执行”]
1.2.5.2 第二次标记【需要执行finalize(),通过筛选】
  • 将该对象放置F-Queue的队列中
  • JVM自动建立一个低优先级的Finalizer线程去执行它(会触发执行,但不一定等待它运行结束)
  • GC对F-Queue中的对象进行标记(对象可通过finalize()拯救自己,重新关联引用链等)
    不建议使用finalize()

1.3 上面讲的是需要回收的堆内存,关于回收方法区(或HotSpot虚拟机中的永久代),效率低

1.3.1 废弃常量

  • 与堆类似,没有任何对象和其它地方引用的常量
  • 随内存回收,被系统清理出常量池

1.3.2 无用的类

  • 该类所有的实例都已经被回收(堆中无该类的实例)
  • 加载该类的ClassLoader已经被回收
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法通过反射访问该类的方法。

2. 如何回收?【垃圾收集算法】

2.1 标记-清除[Mark-Sweep]算法

  • 标记出所有需要回收的对象
  • 统一回收(清除)所有被标记的对象

    缺点:效率不高;标记清除后会产生大量不连续的内存碎片。

2.2 复制[Copying]算法

  • 将可用内存按容量划分为大小相等的两块
  • 每次只使用其中的一块
  • 当使用的这块内存用完了,则将还存活的对象复制到另一块上面
  • 把使用过的那块内存一次性清理掉

    优点:实现简单,运行高效,可按顺序分配内存。
     缺点:内存直接缩小为原来一半,代价太大;对象存活率较高时,效率变低。

2.3 标记-整理[Mark-Compact]算法

  • 标记出所有需要回收的对象
  • 让所有存活的对象都向一端移动(整理)
  • 清理掉存活对象端以外的内存

    适合堆中的老年代的垃圾收集

2.4 分代收集[Generational Collection]算法(商业虚拟机主要采用方法)

  • 根据对象存活周期的不同将内存划分为几块
  • 一般分为新生代和老年代
  • 不同年代采用最适当的收集算法
  • 新生代,一般复制算法
  • 老年代,一般“标记-清理”或“标记-整理”
    具体如何回收,需依据具体的垃圾收集器实现

关于内存泄露

  1. OutOfMemoryError异常,java堆溢出:-Xms ,-Xmx
    对象不断被创建,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
  2. VM Stack溢出。-Xss
  3. 常量池溢出。-XX:PermSize,-XX:MaxPermSize

参考:《深入理解Java虚拟机》

GC基本原理学习(Garbage Collected)相关推荐

  1. 深入理解JVM 一GC(下) G1 Garbage Collector

    文章目录 关于java程序性能 响应能力 吞吐量 G1 Garbage Collector g1收集器的设计目标: G1的设计规划,是要替换掉CMS. 之前的GC收集器对Heap的划分: G1对Hea ...

  2. Tensorflow实践 基本原理学习和框架使用

    Tensorflow 是google大脑小组的工程师们开发的用于机器学习和深度神经网络方面的研究,它通过一个数据流图来进行计算.[本文是对Tensorflow社区资料进行学习和实践,其中文社区还是很好 ...

  3. java垃圾回收GC(学习笔记)

    一.如何确定某个对象是垃圾? public class Main {public static void main(String[] args) {MyObject object1 = new MyO ...

  4. 计算机基本原理 学习笔记(八)

    本篇目录 接上) 十一.软件工程 1.面向对象编程 2.软件开发工具 十二.集成电路&摩尔定律 1.数字暴政 2.集成电路IC 3.印刷电路板 3.光刻技术 4.摩尔定律 5.技术瓶颈 总结 ...

  5. 计算机基本原理 学习笔记(五)

    本篇目录 接上) 七.中央处理器CPU 1.CPU的结构 2. 提高CPU的速度 (1)硬件 (2)指令集 (3)缓存 (4)指令流水线 (5)超标量处理器 (6)多核处理器 3.超级计算机 4.小结 ...

  6. 语音识别基本原理学习

    语音识别基本架构 W表示文字序列,Y表示语音的输入 那么根据公式1,表示语音识别的目标是 在给定语音输入的情况下,找到可能性最大的文字序列 根据贝叶斯公式,可以得到公式2,分母P(Y)表示出现这条语音 ...

  7. MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(一)MOSFET技术

    MOSFET技术 1.器件类型 2.MOSFET模型 3.MOSFET关键参数 4.开关应用 5.开通过程 6.关断过程 7.功率损耗 8.寄生器件的影响 双极晶体管和 MOSFET 晶体管的工作原理 ...

  8. MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(六)变压器耦合栅极驱动

    变压器耦合栅极驱动 1.单端变压器耦合栅极驱动电路 2.双端变压器耦合栅极驱动 在高电压栅极驱动 IC 出现以前,使用栅极驱动变压器是唯一一种在离线或类似高电压电路中驱动高侧开关的可行解决方案. 现在 ...

  9. MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(四)高侧非隔离栅极驱动

    高侧非隔离栅极驱动 1.适用于P沟道的高侧驱动器 2.适用于N沟道的高侧直接驱动器 1.适用于P沟道的高侧驱动器 高侧非隔离栅极驱动可按照所驱动的器件类型或涉及的驱动电路类型来分类.相应地,无论是使用 ...

  10. MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(二)栅极驱动参考

    栅极驱动参考 1.PWM直接驱动 2.双极Totem-Pole驱动器 3.MOSFET Totem-Pole驱动器 4.速度增强电路 5.dv/dt保护 1.PWM直接驱动 在电源应用中,驱动主开关晶 ...

最新文章

  1. 三、Spring Boot在org.springframework.boot组下应用程序启动器
  2. 用 Python 画个生日蛋糕为朋友庆生
  3. 调用系统函数向进程发信号core
  4. AUTOSAR从入门到精通100讲(三十五)-Lin通信协议栈分析三部曲LinTrcv配置及代码分析
  5. 为C++程序添加文件保存加载功能
  6. SYNCHRONIZE_DRAIN的用处
  7. Spring框架整合MyBatis框架
  8. Redis秒杀功能设计与实现
  9. 如何永久的关闭macOS 更新提示?
  10. 设备管理系统未来发展的四大趋势
  11. 【线性代数】第一章 1.3逆矩阵
  12. win10文件资源管理器卡死未响应的完美解决方法
  13. 0DAY零距离(很经典的一片文章,找了好久)
  14. 《新一代视频压缩编码标准H.264/AVC》
  15. java面试答题软件,Java面试题库
  16. 我与小娜(13):LIGO是什么组织?
  17. 穷人翻身远不是钱的事
  18. GM300铁损仪与目前同类机型直读式铁损测试仪的比较
  19. 海思3559U-Boot移植(二):更换新的SPI Nand Flash
  20. linux关闭磁盘缓存,在linux上禁用apache2的所有磁盘缓存

热门文章

  1. EDG获得S11冠军
  2. haml VS erb
  3. 关于公布部分非法刊物的通知及冀职改办字[2006]48号
  4. moocpython答案_中国大学moocPython编程基础题目及答案
  5. 计算房租收入比(1)- scrapy 爬取网上租房信息
  6. 无人驾驶入门——2D检测 基于图片的检测算法(四)
  7. word水印为什么被文字盖住了?
  8. npm ERR! extraneous:的解决方案
  9. linux系统怎么设任务计划,在Linux系统上设置计划任务
  10. activemq启动错误:ERROR | Temporary Store limit is 51200 mb, whilst the temporary data directory