前言:

本文内容:GC简介及回收机制、GC-复制算法、GC-标记压缩清除算法、GC算法总结

推荐免费JVM快速入门视频:【狂神说Java】JVM快速入门篇_哔哩哔哩_bilibili

JVM笔记代码下载地址:

蓝奏云:下载地址 密码:joker

百度云:下载地址 提取码:5xow

GC简介及回收机制

简介

Java GC(Garbage Collec,垃圾收集、回收),垃圾回收站,是将Java中无用的堆对象进行清理,释放内存空间,以免发生内存泄露。

JVM在进行GC时,并不是对这三个区域统一回收。大部分时候,回收都是新生代

  • 新生代
  • 幸存区(from to)
  • 老年区

GC两种类型:轻GC(普通GC)、重GC(全局GC)

引用计数法

JDK1.1之后已经废弃

引用计数器算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器+1,当引用失效的时候,计数器-1,当计数器为 0 的时候,JVM就认为该对象不再被使用,视为 “ 垃圾 “

存在的问题:

  • 不能解决循环引用问题(例如A和B对象互相调用,无法被使用该算法的GC回收,导致内存泄漏)
  • 每次计数器的增加和减少都带来了很多额外的开销

根搜索算法

GC Roots Tracing

根搜索算法是通过一些 GC Roots 对象作为起点,从这些节点开始往下搜索,搜索通过的路径成为引用链(Reference Chain),当一个对象没有被 GC Roots 的引用链连接的时候,说明这个对象是不可用的。

26

GC Roots对象:

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

GC-复制算法

复制算法是把内存分成大小相等的两块,每次使用其中一块,当GC(垃圾回收)的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉,并交换两块内存的角色,完成一次垃圾回收。

25

优点:

  • 没有内存的碎片

缺点:

  • 不适用于存活对象较多的内存,复制的时候会有较多的时间消耗
  • GC过程中会将系统内存空间折半(会有一般的内存浪费)

GC-标记压缩清除算法

标记清除

标记—清除 算法包括两个阶段:标记清除

标记阶段,确定所有要回收的对象(即:未被标记的对象),并做标记;

清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除;

24

缺点:

  • 两个过程的效率都不高
  • 清除之后会产生大量不连续的内存,效率比连续内存空间低

标记压缩

标记—压缩 把所有存活的对象压缩到内存的一端(即:把存活对象往内存的一端移动),然后直接回收边界以外的内存,并且回收完之后的内存空间是连续的。

23

缺点:

  • 压缩阶段占用了系统的消耗,如果标记对象过多的话,损耗可能会很大

GC算法总结

算法总结

内存效率

复制算法>标记清除算法>标记压缩算法

内存整齐度

复制算法=标记压缩算法>标记清除算法

内存利用率

标记压缩算法=标记清除算法>复制算法

没有最好的算法,只有最合适的算法

GC:分代收集算法

年轻代:

  • 存活率低
  • 复制算法

老年代:

  • 区域大,存活率高
  • 标记清除算法(内存碎片不多)+标记压缩算法

拓展

JMM

  1. 什么是JMM?

    JMM(Java Memory Model) Java内存模型

  2. JMM的作用?

    作用:缓存一致性协议,用于定义数据读写的规则

    JMM定义了线程工作内存和主内存(Main Memory)之间的关系;线程之间的共享变量存储在主内存的,每个线程都有一个私有的本地内存(Local Memory)

    解决共享对象可见性的问题:volilate

  3. JMM的规则?

    • 不允许read和load、store和write操作之一单独出现
    • 不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
    • 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
    • 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
    • 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现
    • 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
    • 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
    • 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。