《JVM由浅入深学习【六】 2024-01-10》JVM由简入深学习提升分享
目录
1.jvm堆内存分代模型
介绍一下JVM中堆的垃圾回收过程
当Java应用程序运行时,它在堆内存中分为新生代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation,Java 8之后被元数据区替代)等几个区域。新生代主要用于存放新创建的对象,而垃圾回收主要集中在新生代进行。
堆的结构
-
新生代(Young Generation):包括三个区域,Eden空间和两个Survivor空间(通常命名为S0和S1)。对象首先在Eden空间分配,经过一轮Minor GC 后如果仍然存活,则会被移到Survivor空间,经过多次(minor15次,cms收集器默认6次)后会晋升到老年代。当然可以自己设置次数,下面是官方文档
**注意:**即使对象的年龄尚未达到设定的阈值,如果Survivor区中的空间占用超过50%,这些对象也可能被提前晋升到老年代。这是因为为了避免Survivor区溢出,JVM可能会进行提前晋升。
结论–>动态年龄判断: Survivor 区的对象年龄从小到大进行累加,当累加到 X 年龄 (某个年龄)时占用空间的总和大于50% (可以使用-XX:TargetSurvivorRatio=? 来设置保留多少空闲空间,默认值是 50) ,那么比 X 年龄大的对象都会晋升到老年代 3. 这两个可以查看垃圾回收器默认值 -
老年代(Old Generation):用于存放生命周期较长的对象,经过多次Minor GC(15次的s区域来回回收,这里次数也称为年龄,即15岁进入到老年代)或者经过一次Full GC后的对象会晋升到这个区域。
-
持久代(Permanent Generation):在Java 7及之前,主要用于存放类的元数据信息,包括类的结构、方法等。在Java 8及之后,被元数据区替代。
新生代的垃圾回收流程
新生代的垃圾回收主要分为两个阶段:Minor GC和Full GC。
1. Minor GC
-
触发条件: 当Eden空间满时触发Minor GC。
-
回收过程:
- 首先,垃圾回收器标记并清理Eden空间中不再被引用的对象。
- 存活的对象会被移到Survivor空间,如果Survivor空间满,将会晋升到老年代。
- 清理后,Eden空间变为新的工作区域,等待下一次的对象分配。
-
特点:
- Minor GC的速度较快,因为它只需要清理新生代,而且很多对象在新生代很快被回收。
2. Full GC
-
触发条件: 在老年代空间不足时触发Full GC。或者是由于Minor GC过程中晋升到老年代的平均大小大于老年代的剩余空间时。
-
回收过程:
- Full GC会对整个堆进行清理,包括新生代和老年代。
- 它会停止应用程序的所有线程,进行垃圾回收,因此 Full GC 的耗时较长。
- 对象的引用关系被重新整理,不再被引用的对象所回收。
-
特点:
- Full GC对整个堆进行回收,包括新生代和老年代,速度较慢。
总结
新生代的垃圾回收主要通过Minor GC来清理Eden空间和Survivor空间,快速回收短时间内创建的对象。而Full GC则是针对整个堆内存进行的,较为耗时。这种分代垃圾回收的策略有效提高了垃圾回收的效率,延长了老年代的垃圾回收触发时间,提高了整体的应用程序性能。
什么是老年代空间分配担保机制
-
老年代空间分配担保机制是Java虚拟机为了避免由于新生代Minor GC导致的空间不足而触发一次Full GC,从而提高垃圾回收效率的一种机制。具体而言,它保证了在发生Minor GC时,虚拟机在老年代预留一定的内存空间,以应对新生代对象晋升到老年代的情况。
-
这个机制的设计基于这样一个考虑:在一次Minor GC之前,虚拟机会首先检查老年代的剩余空间是否大于新生代所有对象的总空间,如果是,那么Minor GC可以放心进行。如果不足以容纳新生代所有对象,那么虚拟机会查看老年代中的存活对象是否能够在某个特定的年龄阈值之下就能被全部安置到老年代,如果这个条件成立,同样触发Minor GC,否则,进行一次Full GC。
-
这个担保机制的核心思想是为了尽量避免因为新生代对象晋升导致的Full GC。因为Minor GC的频率通常比Full GC低得多,而且Minor GC的速度更快,因此通过老年代空间分配担保机制,可以在大多数情况下避免因为新生代GC而触发Full GC,提高了垃圾回收的效率。
什么情况下对象会进入老年代?
躲过 15 次 GC之后进入老年代,可通过JVM 参数“-XX:MaxTenuringThreshold”来设 置年龄,默认为 15 岁
2、动态对象年龄判断
3、老年代空间担保机制
4、大对象直接进入老年代
- 大对象是指需要大量连续内存空间的 Java 对象,比如很长的字符串或者是很大的数组或者List 集合,大对象在分配空间时,容易导致内存明明还有不少空间时就提前触发垃圾回收以获得足够的连续空间来存放它们,而当复制对象时,大对象又会引起高额的内存复制开销,为了避免新生代里出现那些大对象,然后屡次躲过 GC 而进行来回复制,此时JVM 就直接把该大对象放入老年代,而不会经过新生代;
- 我们可以通过JVM 参数“-XX:PretenureSizeThreshold”设置多大的对象直接进入老年代,该值为字节数,比如“1048576”字节就是 1MB,该参数表示如果创建一个大于这个大小的对象,比如一个超大的数组或者 List 集合,此时就直接把该大对象放入老年代,而不会经过新生代-XX:PretenureSizeThreshold 参数只对 Serial 和 ParNew 两款新生代收集器有效,其他新生代垃圾收售器不支持该参数,如果必须使用此参数讲行调优,可考虑 ParNew+CMS 的收集器组合。
JVM 运行时数据区 元空间的特点及作用?
- 1、在JDK1.8 开始才出现元空间的概念,之前叫方法区/永久代
- 2、元空间与 Java 堆类似,是线程共享的内存区域
- 3、存储被加载的类信息、常量、静态变量、常量池、即时编译后的代码等数据
- 4、元空间采用的是本地内存,本地内存有多少剩余空间,它就能扩展到多大空间,也可以设置元空间大小;
-XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=20m - 5、元空间很少有 GC 垃圾收集,一般该区域回收条件苛刻,能回收的信息比较少,所以 GC很少来回收
结语:
在Java中,垃圾回收是一项重要的技术,通过自动管理内存资源,使得开发者可以更专注于业务逻辑的实现而不用过多关心内存的分配和释放。通过深入理解垃圾回收机制,我们可以更好地优化代码,提高程序性能,确保系统的稳定性和可维护性。
感谢您的阅读,希望本文对您理解和应用Java中的垃圾回收机制有所帮助。如果有任何疑问或建议,欢迎留言交流,共同学习进步。谢谢!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!