JVM进阶调优系列(3)堆内存的对象什么时候被回收?

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就全都明白了。

上文末尾留了一道题给大家思考:堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就清晰了。

一、虚拟机栈会发生GC吗?

     上一篇文章说到虚拟机栈,虚拟机栈里有局部变量,这个局部变量引用了一个对象,这个对象在堆内存是要被GC回收的,但是虚拟机栈要不要做GC呢,不GC那这个局部变量怎么办?

     实际是不用GC的。线程的虚拟机栈,就是块单独的内存,和堆内存不在一起。虚拟机栈的局部变量,在出栈的时候,就从栈内存里移除去了,出栈完,这个栈内存就清空。所以不需要GC。


二、什么时候会发生YGC?

当JVM想把在年轻代里新增一个对象,但是年轻代空间不足,就会发生YGC。那年轻代空间为何不足呢,如何设置年轻代的大小。我们看一下JVM内存的核心参数。

-Xms:堆内存,最开始堆内存初始大小。

-Xmx:堆内存可以扩张到最大的大小。

-Xmn:堆内存里,年轻代占用的大小,堆内存大小-年轻代大小=就是老年代的空间大小。年轻代里上一篇文章说过里面分:Eden区、SurvivorTo区和SurvivorFrom区,他们按8:1:1的比例划分年轻代的空间。

-XX:MetaspaceSize:元数据空间大小,在JDK8之前对应的是永久代PermSize。

-XX:MaxPermSize:元数据空间可以扩张的最大大小,在JDK8之前对应的永久代MaxPermSize。

-Xss:每个线程虚拟机栈的大小。


所以当-Xmn年轻代里的Eden区空闲内存无法存放新对象,也就是空间不够,这时候就触发YGC,需要将部分对象回收,无法回收的挪到老年代腾出空间。


三、以下代码发生了YGC,哪些对象会被回收哪些不能回收?

package lading.java.jvm;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
/**
 * 说说这个.class 加载到jvm经历的过程,以及在执行过程中,内存如何分配,GC的详细过程
 */
public class Demo002JvmShow {
    public static final String name = "我是类静态变量";
    public static User userA = new User("A");
    public static SoftReference<User> userB = new SoftReference<>(new User("B"));//软引用
    public static WeakReference<User> userC = new WeakReference<>(new User("C"));//弱引用
    public static PhantomReference<Object> objectD = new PhantomReference<>(new Object(),new ReferenceQueue<>());//虚引用
    private int paramInt = 1000;//八大基本类型
    private Object object = new Object();
    private boolean isOk = 10 / 2 == 4 ? true : false;
    public static void main(String[] args) {
        //循环,让堆内存发生YGC
        while (true) {
            Demo002JvmShow show = new Demo002JvmShow();
            User user = new User("拉丁");
            show.paramInt = user.getAge();
        }
    }
}

      JVM 采用的是【可达性分析算法】来判断一个对象是否可以被回收。这个算法的核心就是,通过判断对象是否还有被引用(这里又分强引用、软引用弱引用、虚引用而不同),也就是判断对象是否有GC Roots来进行回收。

      如果你的对象被局部变量、或者类的静态变量引用,GC就不会回收。比如当前执行到方法的show.paramInt = user.getAge(); 里面对象user,由于有main线程的虚拟机栈的user变量引用,这时候YGC是不会回收堆内存里的User对象。



然后对象里有很多变量,来看看哪些会被回收?


强引用的比如name,不能回收。

软引用的userB 对象可能会被回收,因为软引用,如果GC后空间够用就软引用的对象不会被回收,但是GC后空间还不够,那不好意思,软引用的对象也要被回收。

弱引用的userC,被回收。弱引用的对象,一旦发生GC,就会被回收。

如果一个对象没有GC Roots,是否也会被立马回收?

这个不一定。比如对象重写了finalize方法,并赋予新值。GC回收该对象之前,会调用它的finalize方法,如果它还有其他引用尤其是引用了自己,那就不能回收。

四、年轻代GC存活的对象什么时候进入老年代?

     年轻代的对象或者说新对象进入老年代主要有以下3个机制来控制。

    1、动态对象年龄判断机制。

           默认经过15次YGC ,也就是对象的年龄大于15之后,就被挪到老年代。

     2、空间担保机制。

           如果YGC后发现存活的对象比较多,且无法让新对象放到年轻代,然后老年代那边又有足够空间,能保证存下存活的全部对象,就把这些存活对象晋升到老年代存放。

     3、大对象

          如果新增的对象特别大,那这个大对象直接进入老年代。


今天分享到这,具体GC算法我们在下一篇文章分析。

相关文章
|
16天前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
38 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
13天前
|
算法 Java 程序员
内存回收
【10月更文挑战第9天】
33 5
|
16天前
|
Java 测试技术 Android开发
让星星⭐月亮告诉你,强软弱虚引用类型对象在内存足够和内存不足的情况下,面对System.gc()时,被回收情况如何?
本文介绍了Java中四种引用类型(强引用、软引用、弱引用、虚引用)的特点及行为,并通过示例代码展示了在内存充足和不足情况下这些引用类型的不同表现。文中提供了详细的测试方法和步骤,帮助理解不同引用类型在垃圾回收机制中的作用。测试环境为Eclipse + JDK1.8,需配置JVM运行参数以限制内存使用。
26 2
|
16天前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
34 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
4月前
|
存储 分布式计算 Hadoop
HadoopCPU、内存、存储限制
【7月更文挑战第13天】
268 14
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
295 0
|
5天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
13 1
|
9天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
13天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
18天前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
35 4