JAVA虚拟机下篇之垃圾回收机制和算法 以及JAVA中的引用
### 什么是GC(垃圾回收机制)
在系统运行过程中,会产生一些无用的对象,这些对象一直占着内存,如果不对这些对象进行清除,会导致内存资源耗尽. 所以就需要GC垃圾回收机制 回收 堆 和 方法区的内存
### 怎么判断垃圾对象
JVM采用引用计数法和可达性分析法判断一个对象是否需要被回收
#### 引用计数法
每个对象创建的时候,给对象绑定一个计数器,每当一个引用指向这个对象的时候,计数器加一;每当有一个指向改对象的引用被删除时,计数器减一.这样当没有引用指向改对象时,计数器为0,表示这个对象是垃圾了,可以被回收了
优点 : 实现简单,判断效率高
缺点: 不能解决循环依赖问题,所以一般不用
对象A 引用了对象 B 对象B 引用了对象A 那么这两个对象将永远存活
#### 可达性分析法(主流虚拟机采用)
从GC ROOTS 开心向下搜索,搜索走过的路径为引用链,当一个对象到GC ROOTS 没有任何引用链时,则表示该对象不可用,表示可以被回收
优点: 能解决循环依赖问题
和引用计数比,没有缺点
## 三种垃圾回收机制
## Minor GC
发生在新生代的垃圾回收,最频繁,速度也最快
当eden区满时,触发Minor GC .当为一个对象申请内存地址时,发现eben区内存不够用就发生Minor GC
## Major GC
发生在老年代的垃圾回收,通常会伴随着Minor GC ,Major GC通常伴随着 Minor GC 速度比 Minor GC慢
有五种情况会导致Major GC
1. 晋升到老年代的对象大于老年代剩余的空间内存
2. 永久代空间不足
3. 手动执行了System.gc()方法
4. Minor GC之后存活的对象超过了老年代的空间
5. 方法区空间不足(1.8之前)
## Full GC
同等于Major GC
Major GC 与 Full GC都会导致 STW ( stop the world ) ----> 整个世界都停了 所以应该极力避免 Full GC
## 堆中新对象申请内存的过程图
![JVM 堆中新对象申请内存过程](https://img-blog.csdnimg.cn/img_convert/b96a022f1fceff18b038034ac3392cce.png)
## 四种垃圾回收算法
### 复制算法(用于新生代)
将内存平均分为两份,每次只使用其中一部分,当这部分内存满的时候,将其中存活的内存复制到另一半内存空间,然后将这部分内存清空,再去使用另一半内存空间.循环下去
两个幸存者区永远只会使用其中的一个 另外一个永远是空的 from 和 to 相互转换
复制算法与标记整理算法的区别在于 该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个内存区域内
#### 优点:
在存活对象不多的情况下,性能高,能解决内存碎片和java垃圾回收算法之-标记清除 中导致的引用更新问题。
#### 缺点 :
会造成一部分的内存浪费。不过可以根据实际情况,将内存块大小比例适当调整;如果存活对象的数量比较大,复制算法的性能会变得很差
### 标记清除算法(用于老年代)
创建一个对象的时候存储一个标记位,记录状态是死是活
#### 优点
可以解决相互循环引用问题,必要时才进行回收
#### 缺点
标记和清除效率不高,回收时应用需要挂起,.且会造成内存碎片问题
```
内存碎片 : 内存中的存储空间不连续,当需要申请连续的存储空间时无法申请到
```
### 标记整理算法(用于老年代)
创建对象的时候储存一个标记位,记录对象的状态(是死是活),但一阶段不进行对象删除,还要进行二阶段,在二阶段将存活的对象整理起来,放到另一端空间,然后再把剩下的对象全部清除
#### 优点
解决了标记-清除算法造成的内存碎片问题
#### 缺点
由于在二阶段移动了对象,所以需要去更新引用
### 分代算法(JVM采用)
这种算法,根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。可以用抓重点的思路来理解这个算法。
新生代对象朝生夕死,对象数量多,只要重点扫描这个区域,那么就可以大大提高垃圾收集的效率。另外老年代对象存储久,无需经常扫描老年代,避免扫描导致的开销。
在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记清除法或者标记整理算法进行回收
## 垃圾收集器介绍
![image-202203152****3510](https://img-blog.csdnimg.cn/img_convert/dc43aa0cb06b4013644ce4cbf93dd117.png)
## JAVA中的引用
### 强引用
最普遍的引用方式,当内存不足时,JVM宁愿抛出OOM异常,也不会回收强引用的对象
### 软引用
有用但是不是必须的对象,当JVM内存不足时会回收该对象,在Java中用java.lang.ref.SoftReference类来表示
在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生
#### 怎么利用软引用解决内存不足
利用软引用和弱引用解决OOM问题:假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。
设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。
### 弱引用
只要发生GC就会被回收的对象
在java中,用java.lang.ref.WeakReference类来表示 像我们熟系的线程变量类 ThreadLocal中的ThreadLocalMap就是继承了WeakReference
![image-202203152****6758](https://img-blog.csdnimg.cn/img_convert/6c6830e35f7f2a03501bd69fd3785a4f.png)
### 虚引用
如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收的活动
在java中用java.lang.ref.PhantomReference类表示
#Java开发##Java##学习路径#