JVM垃圾回收算法与垃圾回收器

谁要GC?

栈(线程)—不需要GC
堆(对象)——需要GC
方法区(存放字节码常量)——需要GC

GC如何判断对象的存活?

1.使用引用技术算法。
2.可达性分析。

引用计数算法

给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。
优点:快,方便,实现简单。
缺点::对象相互引用时(A.instance=B 同时 B.instance=A),产生循环引用,很难判断对象是否该回收。

可达性分析

判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的。
在这里插入图片描述

作为 GC Roots 的对象包括下面几种:

当前虚拟机栈中局部变量表中的引用的对象
当前本地方法栈中局部变量表中的引用的对象
方法区中类静态属性引用的对象
方法区中的常量引用的对象

finalize

finalize 可以完成对象的拯救,但是 JVM 不保证一定能执行。

各种引用(Reference)

强引用

一般的Object o= new Object()属于强引用,如果有GCRoot强引用,垃圾回收器绝对不会回收它,当内存不足时抛出OOM异常,使程序停止。

/**
 * 可达性分析算法
 */
public class GCRoots {

    Object o =new Object();
    static Object GCRoot1 =new Object(); //GC Roots
    final  static Object GCRoot2 =new Object();
    //
    public static void main(String[] args) {
        //可达
        Object object1 = GCRoot1; //=不是赋值,在对象中是引用,传递的是右边对象的地址
        Object object2 = object1;
        Object object3 = object1;
        Object object4 = object3;
    }
    public void king(){
        //不可达(方法运行完后可回收)
        Object object5 = o;//o不是GCRoots
        Object object6 = object5;
        Object object7 = object5;
    }
    //本地变量表中引用的对象
    public void stack(){
        Object ostack =new Object();    //本地变量表的对象
        Object object9 = ostack;
        //以上object9 在方法没有(运行完)出栈前都是可达的
    }
}

软引用 SoftReference

垃圾回收器在内存充足的时候不会回收它,而在内存不足时会回收它。挼引用非常适合缓存,一些有用但是并非必需,用软引用关联的对象,系统将要发生 OOM 之前,这些对象就会被回收。

/**
 * 软引用 -Xms30m -Xmx30m
 */

public class TestSoftRef {
	//对象
	public static class User{
		public int id = 0;
		public String name = "";
		public User(int id, String name) {
			super();
			this.id = id;
			this.name = name;
		}
		@Override
		public String toString() {
			return "User [id=" + id + ", name=" + name + "]";
		}

	}
	//
	public static void main(String[] args) {
		User u = new User(1,"King"); //new是强引用
		SoftReference<User> userSoft = new SoftReference<User>(u);
		u = null;//干掉强引用,确保这个实例只有userSoft的软引用
		System.out.println(userSoft.get()); //看一下这个对象是否还在
		System.gc();//进行一次GC垃圾回收  千万不要写在业务代码中。
		System.out.println("After gc");
		System.out.println(userSoft.get());
		//往堆中填充数据,导致OOM
		List<byte[]> list = new LinkedList<>();
		try {
			for(int i=0;i<100;i++) {
				System.out.println("*************"+userSoft.get());
				list.add(new byte[1024*1024*1]); //1M的对象
			}
		} catch (Throwable e) {
			//抛出了OOM异常时打印软引用对象
			System.out.println("Exception*************"+userSoft.get());
		}

	}
}

结果

User [id=1, name=King]
[GC (System.gc())  1785K->724K(9728K), 0.0997625 secs]
[Full GC (System.gc())  724K->675K(9728K), 0.0049574 secs]
After gc
User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
*************User [id=1, name=King]
[GC (Allocation Failure) -- 7972K->7980K(9728K), 0.0167924 secs]
[Full GC (Ergonomics)  7980K->7793K(9728K), 0.0068365 secs]
[GC (Allocation Failure) -- 7793K->7793K(9728K), 0.0003036 secs]
[Full GC (Allocation Failure)  7793K->7775K(9728K), 0.0058510 secs]
Exception*************null


弱引用 WeakReference

垃圾回收器在扫描到该对象时,无论内存充足与否,都会回收该对象的内存。

/**
 * 弱引用
 */
public class TestWeakRef {
	public static class User{
		public int id = 0;
		public String name = "";
		public User(int id, String name) {
			super();
			this.id = id;
			this.name = name;
		}
		@Override
		public String toString() {
			return "User [id=" + id + ", name=" + name + "]";
		}

	}

	public static void main(String[] args) {
		User u = new User(1,"King");
		WeakReference<User> userWeak = new WeakReference<User>(u);
		u = null;//干掉强引用,确保这个实例只有userWeak的弱引用
		System.out.println(userWeak.get());
		System.gc();//进行一次GC垃圾回收
		System.out.println("After gc");
		System.out.println(userWeak.get());
	}
}

结果

User [id=1, name=King]
After gc
null

总之软引用 SoftReference 和弱引用 WeakReference,可以用在内存资源紧张的情况下以及创建不是很重要的数据缓存。

什么时候发生GC?

Minor GC

特点: 发生在新生代上,发生的较频繁,执行速度较快
触发条件: Eden 区空间不足\空间分配担保。

Full GC

特点: 主要发生在老年代上(新生代也会回收),较少发生,执行速度较慢
触发条件:
1.调用 System.gc()
2.老年代区域空间不足
3.空间分配担保失败
4.JDK 1.7 及以前的永久代(方法区)空间不足
5.CMS GC 处理浮动垃圾时,如果新生代空间不足,则采用空间分配担保机制,如果老年代空间不足,则触发 Full GC。

复制算法
优点

简单高效,不会出现内存碎片问题

缺点

内存利用率低,只有一半
存活对象较多时效率明显会降低
在这里插入图片描述

标记清除算法

过程:

  1. 首先标记所有需要回收的对象
  2. 统一回收被标记的对象
优点

利用率百分之百

缺点

1.效率低。
2.标记清除后会产生大量不连续的控件碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大时,无法找到足够的连续内存而不得不触发GC。
在这里插入图片描述

标记整理算法
优点

利用率百分之百
没有内存碎片

缺点

标记和清除的效率都不高
效率相对标记-清除要低
在这里插入图片描述

垃圾回收器

分代收集

根据各个年代的特点选取不同的垃圾收集算法,新生代使用复制算法,老年代使用标记整理或者标记-清除算法。

查看垃圾回收器

在命令行输入

java -XX:+PrintCommandLineFlags -version

在这里插入图片描述
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

在这里插入图片描述
在这里插入图片描述
并行:垃圾收集的多线程的同时进行。
并发:垃圾收集的多线程和应用的多线程同时进行。

各种垃圾回收器
Serial/Serial Old

最古老的,单线程,独占式,成熟,适合单 CPU 服务器
-XX:+UseSerialGC 新生代和老年代都用串行收集器
-XX:+UseParNewGC 新生代使用 ParNew,老年代使用 Serial Old
-XX:+UseParallelGC 新生代使用 ParallerGC,老年代使用 Serial Old
在这里插入图片描述

ParNew

和 Serial 基本没区别,唯一的区别:多线程,多 CPU 的,停顿时间比 Serial 少
-XX:+UseParNewGC 新生代使用 ParNew,老年代使用 Serial Old
除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。
在这里插入图片描述

Parallel Scavenge(ParallerGC)/Parallel Old

关注吞吐量的垃圾收集器,高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%。

Concurrent Mark Sweep (CMS)

CMD收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用集中在互联网站或者 B/S 系统的服务端上。
-XX:+UseConcMarkSweepGC ,一般新生代使用 ParNew,老年代的用 CMS

在这里插入图片描述

优点

由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。

缺点

会产生浮动垃圾
采用标记清除算法,内存会有碎片。

G1 垃圾回收器

G1 中重要的参数:
-XX:+UseG1GC 使用 G1 垃圾回收器

内存布局的改变

G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
例如:堆内存8G,分为1000份区域,则每一个区域的空间为8G/1000=8m。

特点

1.空间整合,不会产生内存碎片。
2.可预测的停顿,1000区域一个区域10M*100个(急需回收)
在这里插入图片描述

GC模式
Young GC复制回收算法

选定所有年轻代里的 Region。通过控制年轻代的 region 个数,即年轻代内存大小,来控制 young GC 的时间开销。(复制回收算法)。

Mixed GC

Mixed GC 不是 full GC,如果它无法跟上程序分配内存的速度,就会触发Full CG来手机整个GC Heap.

全局并发标记(Global Concurrent Marking)

初始标记
并发标记
最终标记
回收
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言用于封装代码的单元,可以实现代码的复用和模块化。C语言定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言用于存储同类型数据的结构,可以通过索引访问和修改数组的元素。字符串是C语言用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值