JVM之GC(垃圾回收机制),如何搞挂JVM

前言

在介绍GC之前需要对JVM有着一定的了解,如果还不了解的小伙伴可以点击下方链接详细了解下。

JVM虚拟机详解内部原理

1.GC :Garbage Collection(垃圾回收)

JVM大家都清楚,它有两个主要作用,一个是跨平台,一个是自动化的内存管理。那么这个自动化内存管理就是依赖于JVM中的GC实现的。

它是怎么工作的呢?

  1. Java程序在运行时,GC它会不定时的去堆回收哪些已经“死亡”的对象。堆是存放所有示例对象的地方,是GC主要回收的地方,其次是方法区。

在这里,有些小伙伴就会问了,它是负责回收“死亡”的对象,那它内部是怎么判断该对象是”死亡”的呢?用的一些什么算法呢?

2.GC中如何判断对象是否为垃圾?

2.1:引用计数器法

只要堆里的某个对象被谁引用了一次就+1,如果堆里面的引用计数为0,GC就会认为该对象没有地址引用它,这个对象就算“死亡"了,那么GC就会把它回收。

在这里插入图片描述

但是,这个引用计数算法有一个bug,如果当两个对象互相引用。就好比如A引用B,B引用A。此时就会造成互相引用,这样就会造成GC一直回收不掉这两个对象,从而造成内存泄漏。当然,这种算法在JDK1.8中就被废弃了。
在这里插入图片描述

2.2:根搜索算法

如果堆里的对象被方法区或者栈帧里的变量所引用的话,那么就算这个对象有根,就不算“死亡”。


像循环依赖的bug,根搜索算法已经解决了。


请看下图:
堆中的对象实例5被对象实例3所引用,但是对象实例3未被任何地址所引用,那么它就还算是”死亡“的对象。

在这里插入图片描述
此算法是现在JDK1.8正在使用的

3.GC中如何回收对象?

讲完了GC中如何判断对象是否为需要回收的对象,那么我们在讲讲GC中是如何回收对象的。

GC回收对象分别用到了四种算法:分别为标记清除算法、分段复制算法、标记整理算法、分代收集算法。

3.1:标记清除算法

GC会对那些需要回收的对象进行标记,然后在进行清除。但是这样做有一个弊端,就是在清除完那些需要清除的对象后,有太多的内存碎片。这样就会造成在程序运行一段时间后,某天堆中需要开辟一块连续的内存空间而发现空间不够了,为什么呢?因为内存里它有太多的内存碎片,导致堆中无法分配一块连续的内存空间给该变量。

在这里插入图片描述

3.2:分段复制算法

同样,GC会在回收前标记需要回收的对象,但是,在回收后会将存活的对象和未使用的空间进行划分,就是下图回收后的状态。
优点:完全解决了标记清除算法所造成的内存碎片空间
缺点:大量的移动堆中的内存空间,可能会造成程序的卡顿现象。

在这里插入图片描述

3.3:标记整理算法

此算法清除对象后,会将未使用的内存空间或者存活的对象依次排列整理好。算是上面两种算法的折中方案。

在这里插入图片描述

3.4:分代收集算法

该算法分为三个区域:新生代(Young)、老年代(Old)、永久代:Permanent(方法区)
新生代又分为两个区域:伊甸园(Eden)、生存区(SurvivorSpaces),生存区使用了分段复制算法。
老年代只有一个区域,使用了标记整理算法。
此算法使用年龄来决定对象存放的区域。比如Eden中的某个对象活过了一轮回收,那么它的年龄+1,且分配到From区域。当然,年龄达到一定程度时,就会被分配至老年代。默认阀值为15。

在这里插入图片描述
新生代

  • 伊甸园(Eden):绝大部分刚刚创建的对象都会分配到这里,同时这里也是会被GC重点照顾的地方。在这里能够活过一轮回收的对象就会被加一岁。

  • 生存区(SurvivorSpaces):存放年龄小于15且大于5(其实我也不太清楚大于多少,这里顺便写个数字嘿嘿)的对象,GC来此区域回收的频率比Eden少。

老年代:这里存放的都是生命周期较长的一些对象,回收频率比生存区更低。

永久代:jdk1.8之后,永久代就是现在JVM中的方法区。

分代收集算法是现在主流GC用的最多的一种算法



JVM中的堆溢出

下面给大家展示一段代码JVM中的堆是如何内存溢出的,首先大家要搞清楚,如果内存溢出了,那么肯定是内存泄漏所造成的。所谓内存泄漏就是指:这些对象不会被GC给回收,但是它一直占据着内存空间。

运行前,需要调整一下JVM中堆内存大小。如图:右击>点击Run Configurations>Arguments
在这里插入图片描述
在这里插入图片描述
-Xms:为堆最小内存。-Xmx:为堆最大内存。
在这里插入图片描述
可以看见,报异常为OutOfMemoryError(内存溢出异常)。出现内存溢出时,可以使用JDK自带的一个工具观看JVM中的内存变化。如图
在这里插入图片描述

JVM中栈溢出

其实想要栈溢出很简单,说白了就是栈中调用的方法过多,让栈内存承受不住了就会导致溢出。

在这里插入图片描述
调整栈内存大小:-Xss2048K

JVM中的方法区溢出

想要JVM中的方法区溢出可不简单,因为它需要加载足够多的类,多的让整个方法区都装不下。那么它就崩溃了。我们使用IDEA运行一个SpringBoot项目。

调整方法区内存大小:-XX:MetaspaceSize=5M -XX:MaxMetaspaceSize=15M

在这里插入图片描述

结束语

GC的分享就到这里啦,技术有限。谢谢大家的阅读!阅后点赞,手留余香!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值