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##学习路径#
全部评论

相关推荐

10-31 14:54
已编辑
门头沟学院 算法工程师
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
6
分享
牛客网
牛客企业服务