jvm垃圾回收机制

一。如何判断垃圾可回收

1.引用计数法

引用计数法就是当一个对象被引用时,就对它添加一个引用标记,当一个对象不被引用时就减少一个引用标记,每当需要垃圾回收时,就对引用为0的对象进行回收。

这种方法会产生很多永远不会被回收的垃圾,诸如一个列表中引用了另一个列表,而另一个列表中也引用了它,则会构成循环引用。

2。可达性分析算法

由于循环引用的方式,引用计数法显然不适合用来检索垃圾,这就需要用可达性分析。

可达性分析会将GC root作为根,往下遍历它所有引用的对象,标记结束后,没有被标记的对象都可以被回收

GC root:

system Class 系统类 java.lang.class object hashmap 等

Native Class 本地方法类

Thread 线程正在运行的类 像栈帧里用到的局部变量中引用的对象都可以作为gc root

Busy Monitor sync锁正在使用的作为锁的对象

可以使用eclipse提供的Memory Analyzer (Mat)查看gcroot

3.四种引用

除了直接的引用也就是强引用之外,还有4种引用,这些引用有的会在内存不足的时候,有可能会被回收。

1.软引用

当只有软引用引用该对象的时候,会在第一次垃圾回收之后内存不足的情况下,再次触发垃圾回收,回收这些软引用对象。

除了回收软引用的对象之外,还可以配和引用队列回收软引用本身。

2.弱引用

仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象。

弱引用同样可以配合引用队列来配合回收。

与软引用不同的是,弱引用在第一次垃圾回收时就会被回收,而不会到第二次垃圾回收。

3.虚引用

虚引用必须配合引用队列使用,主要配合ByteBuffer使用。被引用对象回收时,会将虚引用入队,由 Reference Handler 线程调用虚引用相关方法释放直接内存。

4.终结器引用

无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象 暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize 方法,第二次 GC 时才能回收被引用对象。

二。垃圾回收算法

1.标记清除

标记阶段使用可达性算法标记不被回收的对象,清除阶段会将没被标记的对象回收。

缺点:在清除之后会留下很多内存碎片。

2.标记整理

标记整理是标记清除的优化,修正了大量内存碎片这一缺点,但同时在整理阶段会停顿很长时间。

3.标记复制

标记复制把内存分为两块,发生垃圾回收时,会将一边的内存复制到另一边,然后回收剩下的内存。

三。分代回收

在分代回收中,堆内存被分为一下几个代

新生代:

伊甸园区

幸存区s0

幸存区s1

老年代

对象首先被分在伊甸园区,当新生代内存不足时,出发minorGC,将伊甸园区的存活对象copy到s0,然后交换s0和s1。

minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行。

当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)。

当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时 间更长。

当对象不能被放在伊甸园区时,触发minorgc。

如果minorgc中将存货对象放入幸存区不成功,则会直接升级为老年代

当一个对象大到即使触发gc新生代也容纳不下时,就会直接放到老年代中,而不发生gc

子线程的oom不会影响子线程的运行,并且清除线程垃圾

相关参数:

堆初始大小 -Xms

堆最大大小 -Xmx 或 -XX:MaxHeapSize=size

新生代大小 -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )

幸存区比例(动态) -XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy

幸存区比例 -XX:SurvivorRatio=ratio

晋升阈值 -XX:MaxTenuringThreshold=threshold

晋升详情 -XX:+PrintTenuringDistribution

GC详情 -XX:+PrintGCDetails -verbose:gc

FullGC 前 MinorGC -XX:+ScavengeBeforeFullGC

四。垃圾回收器。

1.串行

XX:+UseSerialGC = Serial + SerialOld

serial 是针对新生代的回收器,特点是单线程回收

serialOld是针对老年代的回收期。

2.吞吐量优先

-XX:+UseParallelGC ~ -XX:+UseParallelOldGC

-XX:+UseAdaptiveSizePolicy

-XX:GCTimeRatio=ratio

-XX:MaxGCPauseMillis=ms

-XX:ParallelGCThreads=n

其中parallelGC是针对新生代的,ParallelOldGC是针对老年代的。

在进行标记的时候会产生stw,所有的cpu都会运行垃圾回收,其他时间不会,这样吞吐量就会提升

3.响应时间优先

-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld

-XX:ParallelGCThreads=n ~-XX:ConcGCThreads=threads

-XX:CMSInitiatingOccupancyFraction=percent

-XX:+CMSScavengeBeforeRemark

parNew,是多线程版的serial,而cms是针对老年代的gc,它和ParallelGC不同的地方是它更关注响应时间,也就是减少单位时间内stw的时间

相关推荐
东阳马生架构15 小时前
JVM简介—3.JVM的执行子系统
jvm
程序员志哥21 小时前
JVM系列(十三) -常用调优工具介绍
jvm
后台技术汇21 小时前
JavaAgent技术应用和原理:JVM持久化监控
jvm
程序员志哥1 天前
JVM系列(十二) -常用调优命令汇总
jvm
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭1 天前
聊聊volatile的实现原理?
java·jvm·redis
_LiuYan_1 天前
JVM执行引擎JIT深度剖析
java·jvm
王佑辉1 天前
【jvm】内存泄漏的8种情况
jvm
工业甲酰苯胺1 天前
JVM简介—1.Java内存区域
java·jvm·python
yuanbenshidiaos2 天前
c++---------数据类型
java·jvm·c++