JVM-GC垃圾回收总结

1、JVM的内存模型

根据虚拟机规范,JVM的内存分为 堆、虚拟机栈、本地方法栈、程序计数器、方法区。

JDK 1.8 同 JDK 1.7 比,最大的差别就是: 元数据区取代了永久代 。元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于: 元数据空间并不在虚拟机中,而是使用本地内存。

虚拟机的内存中主要有 程序计数器、虚拟机栈、本地方法栈、堆和方法区。

2、如何判断对象是否可以回收(垃圾判断算法)

引用计数法 : 一个对象被其它变量所引用,计数+1。如果某一个变量不再引用它了,计数-1。 当计数为0时可以被回收。

存在问题:如果发生循环引用,如下图。A、B两个对象都不会被回收,计数都为1。

可达性分析算法 :首先会确定一系列的根对象(GC Root), 按照从上至下的方式搜索被根对象集 合所连接的目标对象是否可达,如果该对象被跟对象直接或间接的引用,就 不能被回收,否则就会被回收。 该算法可以有效地解决在引用计数算法中循 环引用的问题,防止内存泄漏的发生。

哪些对象可以作为GC Root:

虚拟机栈中引用的对象:各个线程被调用的方法中使用到的参数、局部变量等。

本地方法栈内 JNI(通常说的本地方法)引用的对象

方法区中类静态属性引用的对象 比如:Java类的引用类型静态变量

方法区中常量引用的对象比如:字符串常量池(string Table)里的引用

所有被同步锁 synchronized 持有的对象

Java虚拟机内部的引用。

3、垃圾回收算法

1、标记-清除算法(Mark-Sweep)

优点:速度快

缺点: 内存碎片化严重 ,后续可能发生大对象不能找到可利用空间的问题, 会造成内存溢出。

2、标记-整理算法(Mark-Compact)

标记后不是清理对象,而是 将存活对象移向内存的一端 。然后清除端边界外的对象。

优点:没有内存碎片

缺点:速度慢、内存开销大

3、复制算法(Copying)

按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。

优点:速度快、不会有内存碎片

缺点:占用双倍空间

4、Java中的四种引用

强引用:强引用j就是我们常见的普通引用对象,我们程序中几乎所有的引用使用的都是强引 用。只要还有一个强引用指向一个对象,就表明该对象还活着,不能被回收

软引用:一个软引用中的对象,不会很快被JVM回收,当JVM内存不足时,才会对其进行回收

弱引用:比软引用拥有更短的生命周期。在垃圾回收时,只要发现弱引用,不管堆空间是否 足够,都会将对象进行回收。由于垃圾回收器是一个 优先级很低的线程 ,因此 不一定 很快 发现那些只具有 弱引用 的对象。

虚引用: 虚引用 就是 形同虚设 它并不能决定 对象的生命周期。任何时候这个只有虚引用的对 象都有可能被回收。因此,虚引用主要用来跟踪对象的回收,清理被销毁对象的相关 资源。

5、造成内存溢出的常见原因

StackOverFlowError

解释:线程栈内存溢出,

原因:方法递归调用

OutOfMemoryError:Java heap memory

解释:堆内存溢出

原因:大量对象创建撑爆堆区

OutOfMemoryError:Metaspace

解释:方法区溢出

原因:大量类被加载

6、JVM堆内存垃圾回收

Java 的自动 内存管理 主要是针对 对象内存的回收对象内存的分配 。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收。

堆中存放我们new出来的对象,存放的区域就是Eden区域,但这个区域存满以后就会做minor gc, 首先通过可达性分析算法来判断是否是垃圾, 如果能够找到引用就不是垃圾,找不到就是垃圾,minor gc过程中我们有一部分是垃圾一部分不是垃圾,会将这些垃圾对象清除,然后 非垃圾对象会放到survivor区域的to中并且将对象的分代年龄+1 ,分代年龄(用来区分对象生命周期的一种标识,比如parallel默认 对象分代年龄达到15岁就放到老年代中 )。此时一次minor gc结束。我们可以推断出, 老年代做full gc的频率应该远远小于年轻代minor gc ,老年代等到存放对象快满的时候会做full gc,扫描老年代中的对象是否是垃圾,如果都不是并且此时还有对象要进入老年代,那此时就会报OOM(内存溢出错误)。

新生代使用的复制算法,老年代使用的是标记整理算法。

7、什么是SWT?为什么gc要SWT?

指的是GC事件发生过程中, 会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉 ,这个停顿称为STW。可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。

原因很简单,因为java进行垃圾回收时使用可达性分析,从GC Root向下判断对象是否有引用,如果不把所有线程进入safe points并阻塞起来就会出现对象上一秒没有引用被删除,后一秒又出现引用,导致错误的产生。

8、GC 相关参数

JVM
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章