JVM堆空间简述以及GC垃圾回收算法和方式
JVM简述(面试之前看一遍).
堆(非常重要)
堆内存逻辑上分为三个区:
1. 新生代
- 伊甸园区
- 幸存者0区
- 幸存者1区
2.老年代(养老区)
3.元空间(永久区)
元空间也就是方法区,储存类信息+普通常量+静态常量+编译器编译后的代码
GC垃圾回收流程。
- 现在有一个程序在不间断地创建对象,对象都存在在伊甸园区。
- 某个时间段,伊甸园区满了!第一次GC开始了,有n个对象被GC掉了。剩下了1个就留到了幸存者0区,伊甸园区被清空。
- 由于新的对象不断被创建,伊甸园区不断地有新的对象被创建。
- 重复 2.3操作后。
- 再次GC,这次GC会把伊甸园区连带者幸存者0区一起GC。
- GC完之后,发现这次GC下来还有2个对象存活。
- (重点来了!!!!!GC之后,幸存者0区和1区身份有交换,谁是空的,谁才是新的幸存者1区)
- 现在有2个对象存活!存到哪儿????存到了当前的幸存者1区!!(这个时候身份开始交换!),现在这个有对象的幸存者1区就变成了幸存者0区,而原来的幸存者0区从有对象变成了没对象了,就变成了新的!!!!!!幸存者1区
- 为什么要这样做?因为每次GC的时候,都会GC伊甸园区和幸存者0区!!! 这样做就保证有对象的区永远都是幸存者0区!不会漏掉每一个对象!
- 在 幸存者0区和1区中反复存在超过15次的对象,最后将会进入到老年代(养老区)
对象分配过程(TLAB)
对象在堆空间中的结构:
堆空间常用参数总结:
GC垃圾概述
什么是垃圾:
为什么需要垃圾回收:
GC垃圾回收4大算法
Minor GC\ Major GC\Full GC
总得来说,GC用的算法是分代收集算法。
- 次数上频繁GC Young区
- 次数上较少GC Old区
- 基本不动元空间
GC并非每次都对Young ,old ,prem 都进行回收,大部分时间回收的都是young区。
GC因此就分为两种:
1.youngGC:频率高,速度快。
2.FullGc:包含了youngGC,速度比youngGC慢10倍以上。
引用计数法
维护一个计数器,收集每个对象当前还有多少引用,也就是说这个对象当前还有几个地方在用。
如果当前没有被引用了,我们就可以把它GC掉。
JVM一般不采用这个方式。
复制算法
用在youngGC中,JVM采用这个算法。文章上面的==GC垃圾回收流程==中的7-10步就是复制算法。
值得关注的是该算法中的复制次数,默认是15次,超过15次还存活的对象就进入了养老区。
这个复制次数是可以动态设置的。这也是 JVM调优的一个方法,一个重要参数:-XX:MaxTenuringThreshold
标记清除
这种算法存在于Old区
标记压缩
这种算法存在于Old区
主要解决上面标记清除算法所产生的内存碎片!
劣势:耗时也很重
JVM调优(堆调优)
OOM怎么解决?
JVM堆的内存分布图:
JVM中GC示意图:
内存调优1:
我们知道JVM内存最大默认会占用我们机器内存的4/1。 比如一个16G的机器,JVM分到的大概就是接近4个G。
而分配的初始值默认为机器内存的64/1。比如一个16G的机器,JVM分到的大概就是200M
也就是现在默认情况我们的JVM内存大小就在200M到4个G之间。
我们可以手动的设置JVM的这两个参数占比:
-Xms:设置JVM初始分配内存
-Xmx:设置JVM最大分配内存
- 我们经验上,要把Xms和Xmx的值调整成一样!避免内存忽高忽低,导致程序的停顿,造成一些无法预知的异常
在Idea中配置JVM参数:
我们加上我们的配置参数:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
:配置初始值和最大值为:1024m,然后打印GC垃圾回收日志。
内存调优2:
GC过程的调优
首先看看GC日志的分析:
复制算法中我们知道有一个参数,复制次数。
这个复制次数是可以动态设置的。这也是 JVM调优的一个方法,一个重要参数:-XX:MaxTenuringThreshold
我们可以根据我们实际的业务代码去判断对象创建的频率。从而修改我们的复制次数。达到什么目标呢?== 减少对象进入Old区。从而减少OldGc的触发频率,在此基础上尽量减少YoungGc的触发频率。== ,因为OldGc是非常消耗资源的!
好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。