🦊 Java
1、Java基础
1.1 StringBuffer和StringBuilder的区别
1.2 ConcurrentHashMap和TreeMap实现原理
1.3 ArrayList和LinkedList实现原理
1.4 HashSet和TreeSet实现原理
1.5 深拷贝与浅拷贝
1.6 抽象类与接口
2、Java多线程
2.1 并发编程的三大特性
2.2 指令重排
2.3 Volatile原理
2.4 CAS原理
2.5 Java的4种引用级别
2.6 Java中的锁
2.7 Synchronized实现原理
2.8 线程池实现原理
2.9 AQS
2.10 创建线程的方式
2.11 ThreadLocal原理
3、JVM
3.1 判断对象是否存活的方法
3.2 JVM内存结构
3.3 常见的垃圾收集算法有哪些
3.4 指针碰撞和空闲列表
3.5 常见的垃圾收集器有哪些
3.6 内存溢出与内存泄漏的区别
3.7 常用的JVM启动参数有哪些
3.8 反射机制
4、NIO
4.1 概述
5、Spring
5.1 Spring IOC
5.2 Spring AOP
6、SpringBoot
6.1 SpringBoot、SpringCloud的联系与区别
-
+
游客
注册
登录
常见的垃圾收集算法有哪些
## 1 引用计数法 ### 2.1 原理 1. 这种算法会在每一个对象上记录这个对象被引用的次数,只要有任何一个对象引用了该对象,这个对象的计数器就加 1,取消对这个对象的引用时,这个对象的计数器就减 1。 2. 任何一个时刻,如果该对象的计数器为 0,那么这个对象就是可以回收的。 ### 2.2 缺点 1. 如果出现了对象之间的相互引用,这样单纯的引用计数就会出现问题,导致循环引用的对象没办法回收,这时就会出现**内存泄漏**,该释放的没释放,该回收的没回收。 2. 如果依赖关系复杂,计算机的内存资源很可能用满,或者说不够用,这样就可能会导致**内存溢出**。 3. 由于以上原因,在**JVM 中没有使用引用计数法**。 ## 2 JVM 常用 GC 算法 各种垃圾收集器的实现细节虽然不尽相同,但总体而言,垃圾收集器都专注于两件事情: 1. 查找所有存活对象。 2. 抛弃其他部分,即死对象,不再使用的对象。 ### 2.1 标记可达对象(Marking Reacable Objects) 现代 JVM 中所有的 GC 算法,第一步都是找出所有存活的对象,如下图所示: ![e575a130-322d-11ea-9111-a36492d50563 (2054×1134)](/media/202105//1621914623.3531394.png) 1. 首先,有一些特定的对象被指定为**GC 根元素**(Garbage Collection Roots),包括: 1. 当前正在执行的方法里的局部变量和输入参数。 2. 活动线程。 3. 内存中所有类的静态字段。 4. JNI 引用。 2. 其次,GC 遍历内存中整体的对象关系图,从 GC 根元素开始扫描,到直接引用,以及其他对象(通过对象的属性域),所有 GC 访问到的对象都被**标记为存活对象**。 1. 存活对象在上图中用蓝色表示,标记阶段完成后,所有存活对象都被标记了。 2. 而其他对象(上图中灰色部分)就是根元素不可达的,也就是程序不能再使用这些不可达的对象,这样的对象被认为是垃圾,GC 会在接下来的阶段清除他们。 3. 在标记阶段有几个需要注意的地方: 1. 标记阶段需要暂停所有的应用线程,以遍历所有对象的引用关系,因为不暂停就没法跟踪一直在变化的引用关系图,这种情景叫做**全线停顿**(Stop The World Pause),而可以安全暂停线程的点叫做**安全点**,然后,JVM 就可以专心执行清理工作了,**安全点可能由多种因素触发,GC 是触发安全点最常见的原因**。 2. **暂停的时间与堆内存大小、对象的总数没有直接关系,而是由存活对象的数量来决定,所以增加堆内存的大小并不会直接影响标记阶段占用的时间。** ### 2.2 清除(Sweeping) **标记**阶段完成后,GC 进行下一步操作,**删除不可达对象**。 各种 GC 算法在删除不可达对象时略有不同,但总体可分为三类:**清除**(Sweeping)、**整理**(Compacting)和**复制**(Copying)。 #### 2.3.1 标记-清除算法(Mark and Speep) 算法的概念非常简单:**直接忽略所有的垃圾**。也就是说在标记阶段完成后,所有不可达对象占用的内存空间都被认为是空闲的,因此可以用来分配新对象。 该算法的缺点如下: 1. 这种算法需要使用**空闲列表**(Free List)来记录所有的空闲区域,以及每个区域的大小,维护空闲表增加了对象分配时的开销。 2. 命名有很多空闲内存,却可能没有一个区域的大小能够存放需要分配的对象,从而导致分配失败(在 Java 中就是 `OutOfMemoryError`)。 ![f84e7570-322d-11ea-b6b0-159b6a0308ab (1666×608)](/media/202105//1621914623.380117.png) ### 2.3 整理(Compacting) #### 2.3.1 标记-清除-整理算法(Mark-Sweep-Compact) 算法的原理是**将所有被标记的对象(存活对象)迁移到内存空间的起始处,这消除了标记-清除算法的缺点**。 该算法的优缺点如下: * **优点:** 1. 碎片整理之后,分配新对象就很简单,只需要通过**指针碰撞**(Pointer Bumping)即可。 2. 使用这种算法,内存空间剩余的容量一直是清楚的,**不会再导致内存碎片问题**。 * **缺点:** 1. **GC 暂停时间会增加**,因此需要将所有对象复制到另一个地方,然后修改这些对象的引用。 ![034a8040-322e-11ea-a161-cb02df1dc5e6 (1626×644)](/media/202105//1621914623.4386532.png) ### 2.4 复制(Copying) #### 2.4.1 标记-复制算法(Mark and Copy) **标记-复制算法**和**标记-整理算法**十分相似。 * 相同点:**两者都会移动所有存活的对象。** * 区别:**标记-复制算法是将内存移动到另外一个空间:存活区,标记-清除算法只是认为所有不可达对象的空间都是空闲的,可以用来分配新对象。** 标记-复制算法的优缺点如下: * **优点:标记和复制可以同时进行。** * **缺点:需要一个额外的内存空间,来存放所有的存活对象。** ![1033dc20-322e-11ea-b373-e57ecc18caf9 (1604×560)](/media/202105//1621914623.4439304.png)
ricear
2022年7月11日 22:03
©
BY-NC-ND(4.0)
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码