概述
JVM内存回收,我将从以下几方面分析。分别是回收的区域,回收的数据,回收的依据,回收的算法,常见垃圾回收器来彻底聊一下这个问题。
回收的区域
1.JVM内存模型分为线程共享和线程独享
2.线程独享内存生命周期是等于线程的生命周期,是不需要回收的
3.线程共享的内存生命周期是和JVM进程相同的,是需要回收的
回收的数据
堆回收
1.当我们new一个对象或者数组的时候,其实就会将对象和数组的内存分配在堆上
2.当堆上数组和对象已经不需要的时候,这些对象和数组就会被回收,作为重用的内存空间了
方法区回收
1.当我们类加载(加载阶段)到内存,那么类信息和编译后代码就会分配在方法区
2.当我们类加载(准备阶段)到内存,会将静态变量和常量分配在方法区,并且给个初始值
3.当运行时发现一些常量,那么会将数据分配到常量池中,也是属于方法区
3.当类不再使用到,或者一些静态常量和变量使用不到,将被回收
回收的依据
堆回收依据
1.JVM采用可达性分析算法来判断一个堆内对象是否可回收
2.GC ROOT一般指的是我们的方法参数,变量列表的refrence,如果GC ROOT已经不再引用这个对象了,那么说明就可以回收了
3.可达性分析算法,可以解决循环引用问题。
1.对象可达,当内存不足的时候,强引用对象不会被回收,会抛出OOM
2.对象可达,当内存不足的时候,软引用对象会被回收,防止OOM
3.对象可达,被垃圾回收线程扫描到,那么弱引用和虚引用对象会被回收
4.可达性,内存,引用类型来决定是否一个对象被回收
方法区回收依据
1.常量池中数据一般存放字符串,本身也是属于对象,和堆中对象回收条件一样
2.静态变量也是属于一种对象,和堆对象回收条件一样
3.类的不存在实例,类的加载器被回收,类的class对象被回收,那么这个类的信息也可以从方法区清除了
回收的算法
标记清除算法
1.标记,标记可回收对象
2.清除,清除可回收对象
优缺点:
优点:算法简单,容易实现
缺点:回收后,空间碎片化,非常不利于新对象的分配
适用场景:使用存活对象率高的场景
复制算法
1.内存分为两块,一块使用,一块备用
2.复制存活对象到备用内存中,然后整理清除之前整块内存
优缺点:
优点:回收后,不存在内存碎片问题,分配新对象内存快
缺点:内存分成两块,内存缩小为原来一半,需要双倍内存空间
适用场景:使用存活对象率低的场景
标记整理算法
1.标记,标记可回收对象,然后清理可回收对象
2.整理,指的是将存活对象移到一端,然后之外的全部清除
优缺点:
优点:回收后,不存在内存碎片问题,解决了标记清除的缺点
缺点:无
适用场景:使用存活对象率高的场景
分代收集算法
1.我们上面看到,标记清理/标记整理和复制算法针对的分别是可回收对象和存活对象,所以我们要依据这个特点来进行分代回收。
2.年轻代一般都是执行客户端发送请求,然后接口执行,分配临时对象,所以一般存活对象很少,适合用复制算法,基本上不存在存活对象(springmvc+spring)。
3.老年代一般是常驻内存的对象,比如spring容器,启动后,容器依赖的对象不会变的,所以一般全是存活对象,适合标记清理/标记整理算法(springmvc+spring)
常见垃圾回收器
上面是我们常用的垃圾收集器,一般而言是使用分代收集算法,年轻代和老年代各选择一个收集器,当然G1同时支持。