JVM详解之:汇编角度理解本地变量的生命周期

简介: JVM详解之:汇编角度理解本地变量的生命周期

目录



简介



java方法中定义的变量,它的生命周期是什么样的呢?是不是一定要等到方法结束,这个创建的对象才会被回收呢?


带着这个问题我们来看一下今天的这篇文章。


本地变量的生命周期



在类中,变量类型有类变量,成员变量和本地变量。


本地变量指的是定义在方法中的变量,如果我们在方法中定义了一个变量,那么这个变量的生命周期是怎么样的呢?


举个例子:


public void test(){
    Object object = new Object();
    doSomeThingElse(){
        ...
    }
}


在上面的test方法中,定义了一个object本地变量,然后又执行了一个方法。


因为在java中,我们无法直接控制对象的生命周期,对象的回收是由垃圾回收器自动进行的。


通常来说这个object对象会维持到整个test执行结束才会被回收。


现在我们考虑一个特殊的情况,如果doSomeThingElse这个方法是一个while循环,并且永远不会结束,那么这个创建出来的object对象会不会被回收呢?还是一直都存在内存中?


先说我们的结论,JVM非常智能,可以检测出来这种情况,将object对象进行回收。


举例说明



为了能够更好的说明问题,我们自定义一个Test对象,并在其创建和被回收之前打印相应的信息。


public static class Test {
       public Test() {
           System.out.println("创建对象 " + this);
       }
       public void test() {
           System.out.println("测试对象 " + this);
       }
       @Override
       protected void finalize() throws Throwable {
           System.out.println("回收对象 " + this);
       }
    }


然后做两个测试,第一个测试没有无限循环,第二个测试保持无限循环,循环通过一个volatile变量flag来控制:


public static void main(String[] args) throws InterruptedException {
        System.out.println("开始测试1");
        resetFlag();
        flag = true;
        testLocalVariable();
        System.out.println("等待Test1结束");
        Thread.sleep(10000);
        System.out.println("开始测试2");
        flag = true;
        testLocalVariable();
    }


看一下testLocalVariable方法的定义:


public static void testLocalVariable() {
        Test test1 = new Test();
        Test test2 = new Test();
        while (flag) {
            // 啥都不做
        }
        test1.test();
    }


然后我们再启动一个线程做定时的GC。好了一切就绪,我们运行吧:


开始测试1
创建对象 com.flydean.LocalVariableReachability$Test@119d7047
创建对象 com.flydean.LocalVariableReachability$Test@776ec8df
回收对象 com.flydean.LocalVariableReachability$Test@776ec8df
测试对象 com.flydean.LocalVariableReachability$Test@119d7047
等待Test1结束
回收对象 com.flydean.LocalVariableReachability$Test@119d7047
开始测试2
创建对象 com.flydean.LocalVariableReachability$Test@4eec7777
创建对象 com.flydean.LocalVariableReachability$Test@3b07d329
回收对象 com.flydean.LocalVariableReachability$Test@3b07d329


先看测试1的结果,我们可以看到第二个对象在调用test1.test()之前就被回收了。


再看测试2的结果,我们可以看到第二个对象同样被回收了。


结果说明了JVM是足够智能的,可以自行优化本地变量的生命周期。


优化的原因



我们考虑一下,JVM是在什么阶段对本地变量的生命周期进行优化的呢?


很明显,这个优化不是在编译期间进行的,而是在运行期中进行的优化。


我们使用-XX:+PrintAssembly分析一下汇编代码:


image.png


首先说明,本人的汇编语言还是很多年前学过的,如果解释起来有错误的地方,请多多指正。


先说两个概念rbx和r10都是64位CPU的寄存器,r10d是r10的低32位。


先看红框1, 红框1表示rbx中保存的是我们定义的LocalVariableReachability类中的一个Test对象。


再看红框2,红框2表示r10现在保存的是LocalVariableReachability这个类实例。


红框3表示的是进入while循环的时候,ImutableOopMap中存储的对象,大家可以看到里面只有r10和rbx,也就是说只有类实例和其中的一个Test实例。


红框4是什么呢?红框4表示的是一个safe point,也就是垃圾回收的时候的安全点。在这个安全点上如果有不再被使用的对象就会被回收。


因为ImutableOopMap中只存有两个对象,那么剩下的一个Test实例就会被回收。


总结



本文介绍了本地变量的生命周期,并在汇编语言的角度对其进行了解释,如有错误欢迎指正。

相关文章
|
7月前
|
安全 Java
JVM的类的生命周期
JVM的类的生命周期
|
4月前
|
存储 Java 索引
32 位和 64 位 JVM 中 int 变量的大小解析
【8月更文挑战第21天】
257 0
|
7月前
|
存储 Java 程序员
【JVM系列笔记】类生命周期
类的生命周期包括加载、连接(验证、准备、解析)、初始化、使用和卸载五个阶段。加载时,类加载器根据全限定名获取字节码,然后在方法区中创建InstanceKlass对象,并在堆上生成对应的Class对象。连接阶段验证字节码的正确性,准备阶段为静态变量分配内存并赋初始值,解析阶段将符号引用转换为直接引用。初始化阶段执行clinit方法,如静态变量赋值和静态代码块。类的初始化在访问静态成员、使用Class.forName、创建类实例或其子类时触发。
106 1
|
7月前
|
监控 安全 Java
JVM工作原理与实战(七):类的生命周期-初始化阶段
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类的生命周期、类的初始化阶段等内容。
61 5
|
7月前
|
存储 监控 安全
JVM工作原理与实战(五):类的生命周期-加载阶段
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类的生命周期、类的加载阶段等内容。
87 5
|
7月前
|
存储 安全 Java
JVM工作原理与实战(六):类的生命周期-连接阶段
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类的生命周期、类的连接阶段等内容。
67 4
|
存储 Java
【面试题精讲】JVM*类的生命周期*加载阶段
【面试题精讲】JVM*类的生命周期*加载阶段
|
Java API
【面试题精讲】JVM-类的生命周期-连接阶段
【面试题精讲】JVM-类的生命周期-连接阶段
|
存储 缓存 安全
【面试题精讲】JVM-类的生命周期
【面试题精讲】JVM-类的生命周期
|
安全 Java 编译器
【面试题精讲】JVM-类的生命周期-初始化阶段
【面试题精讲】JVM-类的生命周期-初始化阶段