浅析java垃圾回收机制

一、什么是垃圾回收?
1.垃圾回收,顾名思义,便是将已经分配出去的,但却不再使用的内存回收回来,以便能够再次分配。在 Java 虚拟机的语境下,垃圾指的是死亡的对象所占据的堆空间。
垃圾回收只会负责释放那些对象占有的内存,此时对象也就被销毁。
2. 发生地点:一般发生在堆内存中,因为大部分的对象都储存在堆内存中
3.发生时间:程序空闲时间不定时回收
二、无任何对象引用的对象,通过哪些算法找到这些对象呢?
1.引用计数法(不使用)
给对象增加一个引用计数器,
每当有一个地方引用它时,计数器就+1(a = b, b被引用,则b引用的对象计数+1);
当引用失效(一个对象的某个引用超过了生命周期或者被设置为一个新值时)时,计数器就-1;
任何时刻计数器为0的对象就是不能再被使用的。
缺点:无法解决对象的循环引用的问题
2.可达性分析算法
(1)核心思想:通过一系列名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,就证明此对象是不可用的。
(2)

对象Object5-Object7之间虽然彼此还有关联,但是它们到GC Roots是不可达的,因此他们会被判定为可回收对象。
首先,垃圾回收器将某些特殊的对象定义为GC根对象。所谓的GC根对象包括:
(a)java栈和native栈中所引用的对象。
(b)方法区中的常量和静态变量。
(c)活跃线程
接下来,垃圾回收器会对内存中的整个对象图进行遍历,它先从GC根对象开始,然后是根对象引用的其它对象。回收器将访问到的所有对象都标记为存活。
三、垃圾回收算法
1.标记-清除算法
(1)是最基础的收集算法,算法分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,再标记完成后统一回收所有被标记的对象。它的标记过程其实就是可达性分析算法中判定垃圾对象的标记过程。
(2)优点:不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效。
(3)缺点:
(a)效率问题:标记和清除过程的效率都不高。(这种方法需要使用一个空闲列表来记录所有的空闲区域以及大小。对空闲列表的管理会增加分配对象时的工作量。
(b)空间问题:标记清除后会产生大量不连续的碎片,空间碎片太多可能会导致以后再程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前除法另一次垃圾回收。

2.复制算法(新生代回收算法)
(1)复制算法是为了解决“标记-清除”算法的效率问题。
(2)核心思想:他将可用的内存按容量划分为大小相等的两块,每次使用其中的一块,当这块内存需要进行垃圾回收时,会将此区域还存货的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。
(3)优点:性能比较高
缺点:内存利用率低

3.标记-整理算法(老年代回收算法)
让所有的存活对象都向一端移动,然后直接清理掉端边界以外的内存。

4.分代收集算法
当前JVM垃圾收集都采用的是“分代收集”算法,是根据对象存货周期的不同将内存划分为几块。
分代收集算法分为新生代和老年代。
新生代中98%的对象都是"朝生夕死"的,所以并不需要按照1 : 1的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的Eden(伊甸园)空间和两块较小的Survivor(幸存者)空间,每次使用Eden和其中一块Survivor(两个Survivor区域一个称为From区,另一个称为To区域)。当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。当Survivor空间不够用时,需要依赖其他内存(老年代)进行分配担保。
HotSpot (JDK1.3之后使用的java虚拟机) 默认Eden与Survivor的大小比例是8 : 1,也就是说Eden:Survivor From : Survivor To = 8:1:1。所以每次新生代可用内存空间为整个新生代容量的90%,而剩下的10%用来存放回收后存活的对象。
四、垃圾回收算法总结
1.把java堆分为新生代和老年代.
(1)新生代:第一次创建的对象会被分配到此区域。
(2)老年代:经历了一定(HotSpot默认的执行次数是15,经历了15GC就会从新生代移动到老年代)的垃圾回收之后,依然存活下来的对象会移动到老年代。
大对象在创建的时候也会直接进入老年代。(大对象的初始化比较耗时,如果频繁的创建和消耗会带来性能开销,因此最好的实现方式是将他存入GC频率更低的老年代)
2.在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此采用复制算法。
老年代对象存活率更高,没有额外的空间对它进行分配担保,因此采用标记-清除算法或者标记-整理算法。
3.面试:请问了解Minor GC和Full GC,这两种GC有什么不一样吗?
(1)Minor GC :称为新生代GC,指发生在新生代的垃圾回收集。因为java对象大多都是具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也快。
(2)Full GC:老年代GC或者Major GC,指发生在老年代的垃圾会收集。出现了Full GC经常会伴随至少一次的Minor GC。由于老年代中的对象生命周期比较长,因此Major GC并不频繁,一般都是等待老年代满了后才进行Full GC,Major GC的速度一般会比Minor GC慢10倍以上。
五、垃圾回收器:垃圾回收器好不好,主要是看SWT(Stop The World)时间的长短,时间短说明好

(1)Serial:单线程串行的垃圾回收器(新生代:复制算法)

(2)Serial Old:老年代的垃圾回收器,标记-整理算法。
(3)PerNew:并行垃圾回收器(单线程串行垃圾回收器的多线程版本,复制算法)

(4)parallel:并发垃圾回收器(新生代)
GC线程和用户线程可以同时执行。
(5)并发垃圾回收器(老生代)

重点:
(6)CMS:是一种以获取最短回收停顿时间为目标的收集器(并发标记和并发清理可以和用户线程一块执行)
老年代收集器,并发GC。
基于标记-清楚算法实现的。
特点:更少的STW。适用场景:用户交互系统b/s(不能让用户等待太长时间)
优点:并发收集,低停顿。

(7)G1:JDK 11默认的垃圾回收器:唯一一款全区域的垃圾回收器
用在heap memory很大的情况下,把heap划分为很多很多的region块,然后并行的对其进行垃圾回收。
G1垃圾回收器在清除实例所占用的内存空间后,还会做内存压缩。
化整为零的思想,将大的内存划分为无数小的内存。
既不属于新生代,也不属于老年代。
G1最大的优势就在于可预测的停顿时间模型,我们可以自己通过参数-XX:MaxGCPauseMillis来设置允许的停顿时间(默认200ms),G1会收集每个Region的回收之后的空间大小、回收需要的时间,根据评估得到的价值,在后台维护一个优先级列表,然后基于我们设置的停顿时间优先回收价值收益最大的Region。

六、java的内存空间
1.堆:线程共享区域
new Object() 所有的对象都是存在此区域,此区域也是JVM中最大的一块区域。
java垃圾回收就是针对此区域。
2.JVM栈(java虚拟机栈):java方法执行的内存模型(线程私有)
栈中的信息:
(1)局部变量表:存储8大基础的数据类型和对象的引用(指针)
(2)操作栈:每个方法都会对应一个操作栈
(3)动态连接:指向常量池的方法引用
(4)方法返回地址:PC寄存器的地址
3.本地方法栈:线程私有
本地方法栈与虚拟机栈的作用完全一样,他俩的区别无非是本地方法栈为虚拟机使用的Native(c/c++)方法服务,而虚拟机栈为JVM执行的Java方法服务
4.程序计数器:线程私有
用来记录线程执行的行号
5.元空间(JDK 1.8):线程共享
在逻辑上属于JVM,但是这部分的空间已经变成本地空间,并且字符串常量池移动到堆里面了。
JDK 1.7 叫做方法区(永久代)属于JVM
方法区存储:运行时常量池,字符串常量池,类的元信息等

七、类加载机制
(1)加载:根据类路径全名加载二进制流。-》将静态的存储结构转换为运行时的数据结构-》在内存中生成一个此类的方法入口
(2)校验:文件格式进行校验-》字节码校验
验证是连接阶段的第⼀步,这⼀阶段的⽬的是确保Class⽂件的字节 流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运⾏后不会危害虚拟机⾃身的安全。
(3)准备:准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。
(4)解析:初始化final修饰的常量
(5)初始化:此步骤开始将执行权从JVM转移到自己写的程序,开始执行构造函数。
(6)使用
(7)卸载
八、JVM双亲委派模型
1.当加载一个类的时候,这个类不会直接加载,而是将这个加载任务直接交给父类。当找不到父类的时候,自己才尝试去加载。
2.优点:
(1)唯一性(父类执行加载一次)
(2)安全性(会往上找,而上层的类是系统提供的类,避免加载自定义的类)

JMM(java内存模型):让JVM高速运行的一种技术
1.JVM:将程序员可以看懂的代码转化为机器码
2.目的:规范和解决不同操作系统之间的缓存和内存的交换关系。让Java程序在各种平台下都能达到一致的内存访问效果
3.主内存和工作内存(CPU的缓存,离CPU更近,操作更快)

变量声明在主内存中,每个线程在操作变量的时候为了提高性能,从主内存将变量读取到工作内存中,再对工作内存中的变量进行操作,再将操作结果save到主内存中。
4.JMM三大特性:
(1)原子性:要么一块成功,要么一块失败
(2)内存可见性:一个线程操作共享变量之后其他线程是可见的
(3)有序性
5.volatile:
保证:内存可见性,禁止指令重排序
6.面试:说一下JMM
(1)JMM作用:解决不同操作系统在操作内存时的性能差异的,以为它要用到工作内存(CPU的缓存),想让自己的执行性能更加的高
(2)规定:把内存规定为两部分内存:工作内存,主内存(交互方法)
(3)三大特征
(4)可见性和有序性怎么保证:volatile

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值