gc垃圾回收机制

一、jvm 内存划分

JVM java虚拟机 运行Java的容器
jre 运行Java的环境 提供运行时一些类,以及一些类组成的类库
jdk java开发工具 提供javac编译器 Javadoc 生成帮助文档的文件
jvm+运行是的类和库=jre jre+编译器等开发工具=jdk
gc垃圾回收机制_第1张图片

1.编写的java代码是存在硬盘中 硬盘中的数据是永久保存的 运行的java程序会在内存中开辟空间
jvm将内存划分为五块 便于对数据的管理 以及对内存的优化(房子 厨房 客厅 卧室)
2.jvm内存划分
A. 栈内存 所有的局部变量 以及方法在运行的时候都会在栈内存中开辟空间
特点:先进后出 压栈与弹栈
B.堆内存 所有new 的资源 数组 对象都是在存在堆内存中
C.方法区 所有的字节码文件 class文件 以及静态资源都是存在方法区
例如:public static native Thread currentThread();
D.本地方法区 所有使用native 都是存在本地方法区中,就是调用c/c++代码
E. 程序计数器 主要用于控制代码的执行
gc垃圾回收机制_第2张图片
垃圾回收器:
收集并删除未引用的对象。可以通过调用"System.gc()"来触发垃圾回收,但并不保证会确实进行垃圾回收。JVM的垃圾回收只收集哪些由new关键字创建的对象。所以,如果不是用new创建的对象,你可以使用finalize函数来执行清理。
Java本地接口 (JNI): JNI 会与本地方法库进行交互并提供执行引擎所需的本地库。

二、jvm 垃圾回收(GC)

2.1 什么是垃圾回收

刚才我们学习了JVM的内存结构包括五大区域:程序计数器、本都方法区、栈内存、堆内存、方法区。
其中程序计数器、本地方法区、栈内存3个区域随线程而生、随线程而灭,因此这几个区域的内存分配和回收都具备确定性,就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。
而Java堆区和方法区则不一样,这部分内存的分配和回收是动态的,我们需要对不在使用的对象进行处理回收过期的对象(垃圾)从而释放JVM内存空间。

2.2 什么时候回收

在垃圾回收之前,我们必须确定的一件事就是对象是否存活?这就牵扯到了判断对象是否存活的算法
了。

1、引用计数算法:
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器+1,当引用失效,计数器-1.任何时刻
计数器为0的对象就是不可能再被使用的。
优点:实现简单,判定效率高效,被actionscript3和python中广泛应用。
缺点:无法解决对象之间的相互引用问题。java没有采纳
2.可达性分析算法:
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用
链,当一个对象到GCRoots没有任何引用链相连的时候,则证明此对象是不可用的。
比如如下,右侧的对象是到GCRoot时不可达的,可以判定为可回收对象。
gc垃圾回收机制_第3张图片
可达性算法具体理解 1、什么是对象可达?
在java中,可以作为GCRoot的对象包括以下几种:

  • 本地方法区中引用的对象。
  • 方法区中静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法区中JNI引用的对象。
    基于以上,我们可以知道,当当前对象到GCRoot中不可达时候,即会满足被垃圾回收的可能。
    那么是不是这些对象就非死不可,也不一定,此时只能宣判它们存在于一种“缓刑”的阶段,要真正的宣
    告一个对象死亡。至少要经历两次标记:
    第一次:对象可达性分析之后,发现没有与GCRoots相连接,此时会被第一次标记并筛选。
    第二次:对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,此时会被认
    定为没必要执行。

2.3 如何回收

上述的两点讲解之后,我们大概明白了,哪些对象会被回收,以及回收的依据是什么,但回收的这个工
作实现起来并不简单,首先它需要扫描所有的对象,鉴别谁能够被回收,其次在扫描期间需要 ”stop
the world“ 对象能被冻结,不然你刚扫描,他的引用信息有变化,你就等于白做了。
分代回收
内存模型与回收策略
原文链接 年轻代、老年代结构具体理解 内存模型与回收策略
JVMHeap区域(年轻代、老年代)和方法区(永久代)结构图:
gc垃圾回收机制_第4张图片
我们从一个object1来说明其在分代垃圾回收算法中的回收轨迹。
1.object1新建,出生于新生代的Eden区域。
gc垃圾回收机制_第5张图片
2、minor GC,object1 还存活,移动到Fromsuvivor空间,此时还在新生代。
gc垃圾回收机制_第6张图片

3、minor GC,object1 仍然存活,此时会通过复制算法,将object1移动到ToSuv区域,此时object1
的年龄age+1。
gc垃圾回收机制_第7张图片
4、minor GC,object1 仍然存活,此时survivor中和object1同龄的对象并没有达到survivor的一半,
所以此时通过复制算法,将fromSuv和Tosuv 区域进行互换,存活的对象被移动到了Tosuv。
gc垃圾回收机制_第8张图片

5、minor GC,object1 仍然存活,此时survivor中和object1同龄的对象已经达到survivor的一半以上
(toSuv的区域已经满了),object1被移动到了老年代区域。
在这里插入图片描述

6、object1存活一段时间后,发现此时object1不可达GcRoots,而且此时老年代空间比率已经超过了阈
值,触发了majorGC(也可以认为是fullGC,但具体需要垃圾收集器来联系),此时object1被回收了。
fullGC会触发 stop the world。
在这里插入图片描述
在以上的新生代中,我们有提到对象的age,对象存活于survivor状态下,不会立即晋升为老生代对
象,以避免给老生代造成过大的影响,它们必须要满足以下条件才可以晋升:
1、minor gc 之后,存活于survivor 区域的对象的age会+1,当超过(默认)15的时候,转移到
老年代。
2、动态对象,如果survivor空间中相同年龄所有的对象大小的综合和大于survivor空间的一半,
年级大于或等于该年级的对象就可以直接进入老年代。

以上采用分代垃圾收集的思想,对一个对象从存活到死亡所经历的历程。期间,在新生代的时刻,会用
到复制算法,在老年代时,有可能会用到标记-清楚算法(mark-sweep)算法或者标记-整理算法,这
些都是垃圾回收算法基于不同区域的实现,我们看下这几种回收算法的实现原理。

2.4 垃圾回收算法

原文链接 算法具体理解以及垃圾收集器组合优缺点 五、三种基本的GC算法介绍
标记清除法(Mark-Sweep)
标记清除法是垃圾回收算法的思想基础。标记清除算法将垃圾分为两个阶段:标记阶段和清除阶段。
标记阶段,通过根节点,标记所有从根节点开始的可达对象,未标记过的对象就是未被引用的垃圾对
象。
清除阶段,清除所有未被标记的对象。
复制算法(Copying)
复制算法是,将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在适用的内存中
存活对象复制到未使用的内存块,然后清除使用的内存块中所有的对象。
标记压缩算法(Mark-Compact)
标记压缩算法是一种老年代的回收算法。
标记阶段和标记清除算法一致,对可达对象做一次标记。
清理阶段,为了避免内存碎片产生,将所有的存活对象压缩到内存的一端。
2.5 垃圾收集器
垃圾收集器是内存回收的具体实现,不同的厂商提供的垃圾收集器有很大的差别,一般的垃圾收集器都
会作用于不同的分代,需要搭配使用。以下是各种垃圾收集器的组合方式:
gc垃圾回收机制_第9张图片
各种组合的优缺点:
gc垃圾回收机制_第10张图片
gc垃圾回收机制_第11张图片
面试题
面试问题

你可能感兴趣的:(面试知识篇,java)