【JVM|JVM优化(一)】
JVM优化
- 1、 什么是垃圾回收?
- 1.1 Java语言的垃圾回收
- 2、垃圾回收的常见算法
- 2.1 引用计数法
- 2.1.1原理
- 2.1.2、优缺点
- 2.2、标记清除法
- 2.2.1、原理
- 2.2.2、优缺点
- 2.3、标记压缩算法
- 2.3.1、原理
- 2.3.2、优缺点
- 2.4、复制算法
1、 什么是垃圾回收? 程序的运行必然需要申请内存资源,无效的对象资源如果不及时处理就会一直占有内存资源,最终将导致内存溢出,所以对内存资源的管理是非常重要了。
1.1 Java语言的垃圾回收 为了让程序员更专注于代码的实现,而不用过多的考虑内存释放的问题,所以,在Java语
言中,有了自动的垃圾回收机制,也就是我们熟悉的GC。
有了垃圾回收机制后,程序员只需要关心内存的申请即可,内存的释放由系统自动识别
完成。
换句话说,自动的垃圾回收的算法就会变得非常重要了,如果因为算法的不合理,导致
内存资源一直没有释放,同样也可能会导致内存溢出的
2、垃圾回收的常见算法 常见的垃圾回收算法有:引用计数法、标记清除法、标记压缩法、复制算法、分代算法
等
2.1 引用计数法 引用计数是历史最悠久的一种算法,最早George E. Collins在1960的时候首次提出,50
年后的今天,该算法依然被很多编程语言使用
2.1.1原理
假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败
时,对象A的引用计数器就-1,如果对象A的计数器的值为0,就说明对象A没有引用了,
可以被回收。
2.1.2、优缺点
优点:
- 实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否
为0,就可以直接回收。 - 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报
outofmember 错误。 - 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象
缺点: - 每次对象被引用时,都需要去更新计数器,有一点时间开销。
- 浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
- 无法解决循环引用问题。(最大的缺点)
什么是循环引用?
class TestA{
public TestB b;
}
class TestB{
public TestA a;
}
public class Main{
public static void main(String[] args){
A a = new A();
B b = new B();
a.b=b;
b.a=a;
a = null;
b = null;
}
}
虽然a和b都为null,但是由于a和b存在循环引用,这样a和b永远都不会被回收
2.2、标记清除法
标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除
- 标记:从根节点开始标记引用的对象
- 清除:未被标记引用的对象就是垃圾对象,可以被清理
文章图片
这张图代表的是程序运行期间所有对象的状态,它们的标志位全部是0(也就是未标记,
以下默认0就是未标记,1为已标记),假设这会儿有效内存空间耗尽了,JVM将会停止应
用程序的运行并开启GC线程,然后开始进行标记工作,按照根搜索算法,标记完以后,
对象的状态如下图。
文章图片
可以看到,按照根搜索算法,所有从root对象可达的对象就被标记为了存活的对象,此
时已经完成了第一阶段标记。接下来,就要执行第二阶段清除了,那么清除完以后,剩
下的对象以及对象的状态如下图所示
文章图片
可以看到,没有被标记的对象将会回收清除掉,而被标记的对象将会留下,并且会将标
记位重新归0。接下来就不用说了,唤醒停止的程序线程,让程序继续运行即可
2.2.2、优缺点
可以看到,标记清除算法解决了引用计数算法中的循环引用的问题,没有从root节点引
用的对象都会被回收。
同样,标记清除算法也是有缺点的:
- 效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应
用程序,对于交互性要求比较高的应用而言这个体验是非常差的。 - 通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于
内存的各个角落,所以清理出来的内存是不连贯的。
样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标
记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决
了碎片化的问题
2.3.1、原理
文章图片
2.3.2、优缺点
优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多
了一步,对象移动内存位置的步骤,其效率也有有一定的影响。
2.4、复制算法 复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收
时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内
存的角色,完成垃圾的回收。
如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且
效率比较高,反之,则不适合。
文章图片
推荐阅读
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- jvm|JVM调优(线上 JVM GC 频繁耗时长,出现 LongGC 告警,这次排查后想说:还有谁(...))
- java内存区域与内存溢出异常
- 自动内存管理机制
- JVM: 使用 jstack 命令找出 cpu 飙高的原因
- java|JVM之字节码如何在jvm流转
- jvm|从栈帧看字节码是如何在 JVM 中进行流转的
- java|[NIO和Netty] NIO和Netty系列(二): Java Reference详解
- 生活|jrebeleclipse/tomcat 使用方法