博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 中的 GC -- GC基础常识
阅读量:6535 次
发布时间:2019-06-24

本文共 1831 字,大约阅读时间需要 6 分钟。

hot3.png


文中讨论的GC原理均基于 Sun Hotspot JVM,对于不同 JVM 实现可能会有不同。


1. GC (Gabage Collector) 做了什么事情

  • 决定哪些内存需要回收(物理内存的位置)。

  • 决定何时回收这些内存。

  • 决定以什么方式(算法)回收这些内存

##2. GC 回收的不同区域

  • 堆内存(Heap)。
  • 方法区
  • 程序计数器,虚拟机栈,本地方法栈 随线程/方法 运行结束回收。
  • 堆外内存 GC 不负责回收。

##3. GC 回收对象 的依据 : 对象存活算法

  • 引用计数算法

    • 算法说明: 每个对象关联一个引用计数器,当有引用就加1,引用失效时减一,引用为0说明对象可回收
    • 缺陷: 对象循环互相引用不能检测,指的是,多个对象之间互相引用,但是这多个对象与其他外界不再具备任何访问条件的现象
  • 根搜索算法

    • 算法说明: 从一系列 GCRoot 对象向下搜索,搜索走过的路径叫做引用链,当某个对象不能通过引用链被搜索到,就说明可回收
    • GC Root: 1. 虚拟机栈中的引用对象 2. 方法区中静态变量引用的对象 3. 方法区常量池引用的对象 4. 本地方法栈中引用的对象 (JNI)
  • 总结

    • 大多数虚拟机采用的是跟搜索算法

##3. GC 引用的分类

  • 强引用

    • 说明: 使用 new 关键字实例化赋值的对象与变量之间的关系叫做强引用
    • 回收时机: 只要强引用存在,就永远不会被回收
  • 软引用

    • 说明: 描述有作用,但非必需的对象,使用 SoftReference 类来定义
    • 回收时机: 在系统发生内存溢出之前,会被纳入回收范围之内并进行第二次回收
  • 弱引用

    • 说明: 比软引用更弱的引用类型,使用 WeakReference 类来定义
    • 回收时机: 只能存活到下一次垃圾收集发生之前(无论时候内存溢出)
  • 虚引用

    • 说明: 最弱的引用类型,虚引用相当于对象的生命周期是透明的(不会延长对象的生命周期),甚至无法通过虚引用获得对象的实例,唯一的目的就是在被回收的时候收到一个系统通知,使用 PhantomReference 类来定义
    • 回收时机: 相当于不存在,不影响回收时机

##3. GC 回收对象的全过程

  • 堆内存的回收

    • 回收特点: 堆内存主要回收废弃,无用的对象
    • 回收过程:
      1. 根据存活算法扫描到某个对象A已经不被引用并进行第一次标记
      2. 第一次标记之后,筛选该对象是否有必要执行 finalize() 方法,执行的条件是该对象覆盖了finalize() 方法,并且finalize() 方法未被调用过。
      3. 如果没有必要执行finalize() 方法
      4. 如果有必要执行finalize()方法,该对象被放置到一个F-QUEUE队列中,并在一个虚拟机线程去执行,执行的过程中,只保证触发这个方法,不保证等待方法运行结束(防止时间过长、死循环 导致GC回收机制崩溃)
      5. GC 进行第二次扫描,如果发现再次发现对象A 不被引用,那么就将执行回收过程;这里如果对象A在步骤 4 中执行finalize() 方法的时候,在代码里面重新与GCRoot引用链获得的访问关系,这次扫描将不会被扫描到,但是因为finalize()已经被执行过了,所以下次一旦被扫描到,就不能再通过finalize()来GC逃逸了
  • 方法区内存的回收

    • 回收特点: 方法区内存主要回收废弃,不用的 常量,类,接口

    • 回收常量: 加入对于某个常量池中的字符串,已经没有任何该类型(String)的对象是这个值,也没有其他地方引用到了这个字面量,如果这个时候发生内存回收,而且有必要(这个根据情具体实现况判断什么是有必要,比如常量的生命时间,常量的使用频率等),这个常量将被回收

    -回收类(包括它的接口,方法名,字段): 1. 该类的实例对象都已经被回收 2. 加载该类的ClassLoader也已经被回收 3. 该类的Class 对象没有被任何地方引用,也就是无法通过反射来访问这个类 4. 当满足了上述3个条件,仅仅是说明可以回收了,不代表会回收,具体看不同虚拟机的限定条件 5. 类回收的主要场景: 对于应用大量 反射,动态代理,CGLib 等bytecode的框架以及场景,动态生成JSP和OSGI等频繁定义用户ClassLoader的场景,都有可能产生大量的自动生成的类加载行为,为了防止永久区溢出,需要对这种生成的类进行卸载

转载于:https://my.oschina.net/samuelzuuka/blog/739891

你可能感兴趣的文章