垃圾回收GC

gc
什么是垃圾:
没有引用的对象就是垃圾
c和c ➕➕ 不需要你自己清理垃圾

tlab 线程本地缓存 不用和其他线程竞争


怎么去定位垃圾?
1.根可达算法(解决对象循环引用的问题
问题:哪些常见的类是根?一般是初始化加载的对象。推荐 《jvm虚拟机规范》
2.对象引用次数统计:python就是用的refrence count 。但是不足之处是:无法解决循环应用的问题。

内存分为三类:
存活对象块
未使用块
可回收块

gc回收算法(声明:各个算法没有优劣之分)
1.标记清除🆑 mark sweep
标记哪些是垃圾
产生内存碎片,导致内存不连续,假如分配一个大的对象,可能没有足够连续的内存空间
产生碎片🧩

2.拷贝 copying
不用标记,把内存️分为️,把一边的存活对象全部拷贝到另一边,然后把本身这边进行清除,这样这边全部内存块都可用了,例如:eden就会把对象拷贝到survivor 区,eden整块就连续可用了,nice
造成空间浪费

3.标记压缩 🗜️mark compact
先标记出垃圾对象,然后把后面的存活对象挪到垃圾对象那里去,使得内存块连续,这样就特别利于新对象的分配
效率偏低

jvm规范 
甲骨文的: hotspot

调优第一步:确定哪个版本 ,确定使用的是哪种垃圾回收器

内存模型:分代模型 不分代模型
分代模型:新生代 老年代

新生代垃圾回收器,一般采用copy垃圾回收算法。因为通常这个阶段存活对象比较少,copy效率更高些

老年代垃圾回收器,一般采用mark sweep和mark conpact算法

堆内存逻辑分区
(一开始的分代算法到现在发展出来的不分代算法)
分代算法中不同代采用不同的回收算法♻️效率是最高的

新生代:eden survivor survivor 8:1:1
老年代:tenured

默认新生代老年代 1:2
eden区里面的存活对象在回收的时候采用拷贝算法,1.第一次拷贝到第一个survivor区,接着,2.第二次拷贝到第二个survivor 区,第一个survivor 区域任还存活对象也一块拷贝到第二个survivor区,同时,年龄加一。
当达到一定岁的时候对象还顽强的活着,那么就会将对象挪到 老年区 。直到老年区存放不了,就会发起一次full gc。
至于多少岁取决于采用的是啥垃圾回收器
cms6岁 其他的一般15岁

随着内存越来越大:
serial parallel scavenge cms g1


serial:新生代垃圾回收器
单线程进行垃圾回收,当serial线程工作的时候,你的作业业务线程此时停止!这就是著名的stop the world ,简称STW,
适应于几m到几十m大小的内存。现在基本废了
对应的老年代回收器叫做serial old,原理一样,算法不一样。


随着内存越来越大,单个线程回收会比较吃力,现象是可能客户端会有卡顿的现象,就出现了对应的多线程回收器♻️。

parallel scavenge:新生代垃圾回收器
多线程进行垃圾回收,和serial一样,工作的时候,其余业务线程停止。stw。
适应于内存大小在几g到几十g吧!现在还有在用。
对应的老年代回收器叫做parallel old,原理一样

️线程太多了,cpu的上下文切换,效率反而不高

️上面提到的不同代的回收器 它们的回收算法是不一样的,一般新生回收器采用 拷贝 的形式,而老年代采用标记清除或标记压缩

还有另外两个分代垃圾回收器,一个是新生代的parnew。和老年代的cms,注意parnew和ps基本一样。下面重点说一下cms,因为他是未来垃圾回收器的一个发展方向,简单来说,就是边回收边工作。减少stw这个耗时的状态。

简单说一下stw,当处于stw状态时候,业务线程停止,因此我们应该尽量减少stw的发生

cms:老年代垃圾回收器
初始标记,标记找到对象的根stw
并发标记,标记找到每个根对象下面的垃圾

重新标记,对并发标记的垃圾对象进行重新标记,stw ,这一步主要是修正 并发标记 时候的错误标记,采用的是三色标记法

并发清理,清理垃圾,这个同时会有浮动垃圾产生


jvm调优 
调吞吐量 
调响应时间,降低stw


cms的重新标记,
使用了一个三色标记算法 ➕ 写屏障➕增量更新
分析:三色是一个逻辑概念,黑色代表对象本身以及成员变量均已标记完成✅,灰色代表对象标记完成,但是成员变量还未来得及标记,白色代表对象和其成员变量均为标记。

为了解决并发标记过程中标记为垃圾的对象,又被其他对象所引用问题。我们这个时候把重新去引用垃圾的这个对象再次标记为灰色, 这里就涉及到一个写屏障的概念。简单来说,就是你的每一次引用都会进行跟踪,然后进行修改。

这个还是存在一个隐蔽的问题,重新标记步骤是多个垃圾回收线程一起工作,会存在多个回收线程对一个对象进行回收标记。这样就可能黑 灰 黑 这种情况。还是会出现误标的情况。

g1垃圾回收器
三色标记算法➕SATB ➕写屏障
satb和cms的增量更新区别是,在灰色引用指向白色引用对象消失的时候,会记录一下。最后一次扫描会把对象再拉出来看是否️引用。

zgc垃圾回收器
coloredpointer 颜色指针算法 加读屏障

二、调优
什么时候需要调优?
1.解决jvm在运行时出现的问题,比如oom
oom out of memory
频繁的gc ,jvm直接崩掉。这个时候就需要调优。

2.时不时体验上卡顿,时不时内存占用标高,也需要调优。

要进行调优之前,需要先了解jvm调优参数

java -XX:printflagsfinal

java -XX:printflagsinnitialize


-Xms 初始化堆大小
-Xmx 最大堆大小

避免不必要的扩容和收缩,在不断产生
新的对象的时候,jvm需要花费资源来计算 下一步扩多大,不用了需要考虑下一步缩回到多少。无疑资源浪费。

-XX:+PrintGC 把gc的过程打印出来

jstack 进程号 :打印线程栈 ,检测死锁
可以从多个线程找有问题的线程

案例:datax导大批量数据的时候,出现数据库连接锁死的情况

阿里规范每个线程都得有意义的线程名=》方便定位问题


jinfo 线程名 虚拟机的信息  

jstack -gc 进程号 输出一些gc的情况
新生代
老年代各占多少 等等

其实jdk自带了一个图形界面 bin/jvisualVM
(服务器上这种图形调优是不大可能的),上线之前的压测是可以图形界面调优的



jmap命令。jvm是会暂停的

工作中运行最多的是
arthas

出现oom已经是调错了,需要自己想办法把问题找出来


三、系统上线前预估并发情况
arthas
java -jar boot.jar可以挂到你的系统进程进行观察

dashbored 命令,动态字符型界面展示你的进程信息
主要包含:繁忙的线程 内存 等等在干嘛

jvm命令 信息更全

thread命令 线程信息类似 jstack
thread | grep main 过滤

thread -b命令直接可以查看是否️产生死锁的线程,直接能够找出来

更多 thread -help

sc命令 sc * 显示jar包运行加载的所有类,找出关心的类,sm找出关心的方法

几个观察方法的命令:
trace 命令 跟踪方法执行的时间,如果发现执行时间很长,就说明有问题

monitor 命令 跟着方法的运行数据

哪些参数值 传递进去了,哪些值反回来了

一旦你的程序内存不断增长,这个时候也不停的fullgc,知道oom,程序挂掉

每个垃圾回收器产生的日志是不一样的,可以从定位日志来发现问题在哪里🧐

内存泄漏 memory leak 没什么用 但是也不释放,这样的对象多了就会oom ,站着桌子不吃饭

内存溢出oom

就开始找是哪些对象 没用,但是也没释放呢

jmap命令 java 内存 分析。
直接把堆里面的对象纠出来,
jmap -histo 进程号

🈴️
oom问题解决关键:是哪些对象在不断占用内存,找到对应代码,解决bug
方法就是 arthas 和 jmap -histo 命令

jmap会把线程进程停掉。堆特别大,是不合适的。
分析内存转储文件,堆文件

1.一个jmap命令就可以生成堆文件
2.arthas 的 headdump 命令 ,都会产生一次fullgc ,

生成了一个堆文件,把堆文件下载下来使用bin/jvisualVM打开分析

生产环境绝大多数情况不能直接把堆内容导出来,,导出的过程工作线程都要会停止,stw,答案:很多服务器都是高可用的

一旦oom自动产生堆转储文件。

另一种在线定位,使用arthas

还可以使用在测试环境压测,定位出问题

arthas 王炸命令 jad 
反编译功能 


redefine 命令可以替换运行的class 临时解决

十个面试oom案例


四、三色标记算法
黑色:自己和儿子对象都标记完毕
灰色:只有自己标记完毕 儿子对象还没标记
白色:都没标记好

 
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值