JVM垃圾回收器

堆和栈(栈帧)内存概念:

在程序运行时,会在内存中分为两块区域,一个是堆,一个是栈,当程序运行到一个方法时就会生成一个对应的栈空间,由一个栈帧指向它(这里面说的是单线程,一个线程就会有一个对应的栈内存)。当成方法生成一个对象时,就会在对应方法的栈中,生成一个对象,但是对象的存储空间是在堆中,栈中对象指向堆中内存空间。当一个方法执行完毕后,对应的栈帧就会指向像一个方法,执行完毕的方法栈内存,就会弹出(栈属于是一种先进先出的数据结构,类似于桶状)。

在C和C++时期容易出现的内存问题

野指针:引起的问题也就是我们常见的空指针异常,当一个方法中生成一个对象时,该对象会在内存中开辟一个堆空间,当另一个方法中也存在该引用对象时,也会指向该内存空间,当其中一个方法中的对象将该内存空间删除之后,但另一个方法还在引用该对象,但是内存空间已经不存在了,就会引起空指针异常

多线程:一个线程会开辟一个栈空间,多个线程会开辟多个栈空间,当这些栈中间中的对象都指向一个内存堆空间时,只要出现了上述的野指针问题时,就会变得更加难以排查问题,多个栈空间对象,引用同一个不存在的堆内存空间。

内存泄漏和内存溢出概念:

当堆空间中的内存空间忘记删除时,但是还没有对象引用该内存空间,就会出现内存泄漏,而内存泄漏过多时,就会导致新生成的对象,没有内存去存放该对象对应的内存空间了,这种现象就叫做内存溢出。这种问题解决起来一般是重启

多次释放概念:

当一个线程释放了一块内存空间时,另一个线程可能会引用该内存空间,当多次释放时,会将其他线程占用的这块内存空间再次删除,导致新占用的线程出现问题。

GC(垃圾回收)算法

由于内存空间的发展:包含三种:标记算法,复制算法,标记压缩算法

标记算法:标记不在由对象引用的内存,视为垃圾,就会被清理掉

注:容易出现内存碎片化

复制算法:将堆内存空间分为两部分,每次只能使用其中一块区域,当一块区域要满的时候,就会将存活的对象指向的内存空间,转移到另一块区域

注:浪费内存 

标记压缩算法:由于上述算法都会出现不同的问题,标记算法采用在标记期间就会将存活内存顺序排序,将垃圾整理出来,在统一回收

注:效率是三种算法中最低的

分代垃圾回收

大致概念:

分代主要将堆内存空间分为新生代和年老代,当刚new的对象就会将其内存空间分别到新生代,每次新生代垃圾回收时,就会给这些还存活的对象“岁数+1”,当到达一定程度后就会放到年老代中,年老代中的对象引用的内存空间不会经常检查回收,新生代会经常检查回收。

怎么运行的呢?

首先新生代会将内存空间分为8:1:1这样大小的内存空间,其中8占比的内存空间命名为Eden(伊甸园),剩下的20%空间大小分为两部分区域,都叫Survivor区(幸存者),下面我们用Survivor1和Survivor2表示。

其次我们会将新生成的对象放到新生代中的Eden区,当Eden区满了的时候就会使用复制算法将垃圾清理,存活的对象放到Survivor1中,当下一次Eden区满之后,就会将存活对象和Survivor中的存活对象一起放到Survivor2中,下次在都放到Survivor1中,反复循环。在新生代中最为垃圾处理回收的GC称为YGC,老年代中的GC称为Major GC。当Survivor中其中一个区满的情况下就会将存活对象放到年老代,年老代GC采用的算法为标记算法和标记压缩算法。

采用分代回收JVM中垃圾处理器的发展历史:

1.Serial收集器:主要理解就是采用的是单线程的回收,但是当GC线程工作时就会将业务线程暂停(STW),所以只是用于小型应用。

2.Parallel收集器:主要理解就是采用的多线程的回收,但是当GC线程工作时业务线程也会暂停,适用于中等项目开发。

JDK8默认采用的就是Seriall

3.CMS收集器:最牛的在于CMS在GC垃圾回收阶段,业务线程相对于其他两种只会短暂暂停一段时间,可以理解为GC线程与业务线程同时运行,保证效率。

CMS运行四个阶段

1.初始标记:在该阶段会暂停业务进程,垃圾回收进程就会标记那些对象引用的内存地址(根对象)。

2.并发标记:(该阶段采用三色标记算法)在系统运行的同时进行标记,但是这样做的会出现漏标的问题。

3.重新标记:将业务进程再次暂停,垃圾回收进程重新进行标记。

4.并发清除:将前几个过程中那些没有标记的进行清理。

三色标记算法

由于线程在运行时是分片的,一次只能运行一个线程,每次标记的线程不固定,所有需要标记下上次标记到的位置,以便下次在进行标记。

三色算法将对象分为三种不同颜色:

白色:表示对象尚未被扫描和标记

灰色:表示对象已经被扫描,但是其引用对象尚未标记

黑色:表示对象已经被扫描并且其引用对象也已经被扫描

出现的问题以及解决:

有这样一种场景,假设A对象为黑色,B对象为灰色,C对象为白色,其中A引用B,B引用C,正常来说下次CMS来扫描的话就会将C标记为黑色,B标记为黑色,但是A已经标记过就不会再次标记。这是问题就会产生,假设这时业务代码执行A去引用C,BC之间的引用断开,那么由于A是黑色那器引用对象就不会被再次标记,最终C对象(白色)会被当做垃圾处理掉。

解决:就是在A对象去引用一个新的C对象时将其的颜色变为灰色,这样垃圾回收下次在进来就会重新标记A,从而找到A的引用对象并进行标记。(这种解决方法就叫做Incremental Update)

CMS天生的bug

假设有两个垃圾处理线程m1和m2,在A对象中有两个成员属性 a1 a2,m1来标记时刚标记完a1还正在标记a2(a1在m1眼里已经扫描过了),这时业务线程将a1属性指向了一个D对象(白色),这时切换到了m2垃圾回收线程,将A标记为灰色,将要标记A下面的引用对象。但是这时m2没有机会执行呢,m1过来执行,但是m1认为a1已经扫描过了,扫描完a2就将对象A标记为黑色,所以D对象就会出现漏标的情况。

漏标怎么解决呢?

在重新标记阶段重头到尾标记一遍那些在并发标记阶段产生变化的对象,但是会产生增加停顿时间。

G1垃圾回收器(JDK9开始默认的回收器)

注:G1是物理上不分代,概念上分代

G1不在采用分代存储,而是分区管理,将堆内存分为等分的区域(Region),每个区域可以是Eden区、Survivor区或Old区。这种分区的方式有助于减少垃圾回收的范围,提高回收效率。

G1使用了一种基于区域的回收策略,称为“Garbage-First”,它会优先选择包含最多垃圾对象的区域进行回收。

Humongous是一个特殊的概念,用于表示超大对象。当一个对象的大小超过了一个区域的一半时,它就被认为是一个Humongous对象

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值