StackMapTable是否会影响垃圾回收行为? [英] Does the StackMapTable affect the garbage collection behavior?

查看:102
本文介绍了StackMapTable是否会影响垃圾回收行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的代码:

public class TestGC {
    private static final int _10MB = 10 * 1024 * 1024;  // 10MB
    public static void main(String[] args) {
        test1();
        // test2();
    }

    public static void test1() {
        int i = 1;
        if (i > 0) {
            byte[] data = new byte[_10MB];
        }
        System.gc();
    }

    public static void test2() {
        if (true) {
            byte[] data = new byte[_10MB];
        }
        System.gc();
    }
}

我用jvm选项 -verbose:gc 运行它,我的java env:

I run it with jvm option -verbose:gc, My java env:

java版本"1.7.0_79"

java version "1.7.0_79"

Java(TM)SE运行时环境(内部版本1.7.0_79-b15)

Java(TM) SE Runtime Environment (build 1.7.0_79-b15)

Java HotSpot(TM)64位服务器VM(内部版本24.79-b02,混合模式)

Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)

案例1:

在调用方法 test1()的情况下运行,控制台输出:

CASE-1:

Run with method test1() invoked, console output:

[GC 13312K->616K(116736K), 0.0014246 secs]
[Full GC 616K->554K(116736K), 0.0125266 secs]

data var由JVM收集.

data var is collected by JVM.

在调用方法 test2()的情况下运行,控制台输出:

Run with method test2() invoked, console output:

[GC 13312K->10936K(116736K), 0.0092033 secs]
[Full GC 10936K->10788K(116736K), 0.0155626 secs]

数据 var未收集.

我通过命令 javap 生成方法的字节码:

I generate bytecode for methods by command javap:

public static void test1();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
    stack=1, locals=2, args_size=0
        0: iconst_1
        1: istore_0
        2: iload_0
        3: ifle          11
        6: ldc           #3                  // int 10485760
        8: newarray       byte
        10: astore_1
        11: invokestatic  #4                  // Method java/lang/System.gc:()V
        14: return
    LineNumberTable:
        line 11: 0
        line 12: 2
        line 13: 6
        line 15: 11
        line 16: 14
    LocalVariableTable:
        Start  Length  Slot  Name   Signature
            11       0     1  data   [B
            2      13     0     i   I
    StackMapTable: number_of_entries = 1
        frame_type = 252 /* append */
            offset_delta = 11
        locals = [ int ]

test2()

public static void test2();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
    stack=1, locals=1, args_size=0
        0: ldc           #3                  // int 10485760
        2: newarray       byte
        4: astore_0
        5: invokestatic  #4                  // Method java/lang/System.gc:()V
        8: return
    LineNumberTable:
        line 20: 0
        line 22: 5
        line 23: 8
    LocalVariableTable:
        Start  Length  Slot  Name   Signature
            5       0     0  data   [B

我的猜测是:当执行方法 test1()来堆叠地图框架时,将重置局部变量并清除导致slot_1(位于 data 的位置).

My guess is: When method test1() execute to stack map frame, the local variables is reset and lead to slot_1(data located) is cleared.

有人可以提供详细的解释吗?

Someone can give a detail explain?

推荐答案

局部变量的范围是编译时的事情.对于字节码,仅重要的是哪个值是最近写入局部变量索引的.对于垃圾收集器来说,仅重要的是,随后可以访问哪个值.

The scope of local variables is a compile-time thing. For the byte code, it only matters, which value was most recently written to a local variable index. For the garbage collector, it only matters, which value may subsequently get accessed.

但是检测到随后不使用值,可能取决于代码的编译/优化级别.在您的简单测试中,代码将始终以解释方式运行,因此JVM并不总是检测到所创建的数组实际上未被使用.运行 -Xcomp 进行测试时,它将始终立即被收集.

But detecting that a value is not subsequently used, may depend on the compilation/optimization level of the code. In your simple test, the code will always run interpreted, so the JVM does not always detect that the created array is actually unused. When you run you test with -Xcomp, it will always get collected immediately.

您发现的行为取决于字节码中找到的条件分支,而不取决于堆栈映射的存在,您可以通过使用 -target 1.5 进行编译来轻松验证(也需要 -source 1.5 ),因此在已编译的类文件中不存在堆栈映射,而是在相同的运行时环境中运行;行为不会改变.

The behavior you have discovered depends on the conditional branches found in the byte code, but not on the presence of stack maps, which you can easily verify by compiling with -target 1.5 (also needs -source 1.5), so that no stack maps are present in the compiled class file, but run on the same runtime environment; the behavior doesn’t change.

请注意,您的

if (true) {
    byte[] data = new byte[_10MB];
}
System.gc();

{
    byte[] data = new byte[_10MB];
}
System.gc();

当您在编译时常量上分支时.但是由于您没有覆盖值,例如通过在作用域末尾创建并使用另一个变量,字节码与

as you are branching over a compile-time constant. But since you are not overwriting the value, e.g. by creating and using another variable after the end of the scope, the byte code doesn’t differ from

byte[] data = new byte[_10MB];
System.gc();

除非已编译代码,否则所有这些变体都表现出与不收集仍由堆栈框架引用的数组相同的行为.

All these variants exhibit the same behavior of not collecting the array still referenced by the stack frame, unless the code got compiled.

相反,

int i = 1;
if (i > 0) {
    byte[] data = new byte[_10MB];
}
System.gc();

带有条件分支,因此在 System.gc()点,不能使用数组引用,因为代码点可能通过未初始化此变量的路径到达

bears a conditional branch, so at the System.gc() point, the array reference can’t be used, as the code point might get reached through a path where this variable is not initialized.

同样,数组是用

for(boolean b=true; b; b=!b) {
    byte[] data = new byte[_10MB];
}
System.gc();

因为条件分支可能会绕过变量初始化,而使用

as the conditional branch may bypass the variable initialization, while with

do {
    byte[] data = new byte[_10MB];
} while(false);
System.gc();

未收集数组,因为始终会初始化变量.

the array is not collected, as the variable is always initialized.

还有,

public static void test1() {
    int i = 1;
    if (i > 0) {
        byte[] data = new byte[_10MB];
    }
    else {
        byte[] data = new byte[_10MB];
    }
    System.gc();
}

不收集数组,因为始终会初始化变量,而不管代码采用哪个分支.如前所述,仅在解释执行中.

the array is not collected, as the variables is always initialized, regardless of which branch the code takes. As said, only in interpreted execution.

这表明此处未使用堆栈映射 ,因为堆栈映射明确声明在分支合并点没有 byte [] 变量,就像原始的 test1()变体一样.

This is a sign that the stack map is not used here, as the stack map clearly declares, that there is no byte[] variable at the branch merge point, like in your original test1() variant.

这篇关于StackMapTable是否会影响垃圾回收行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆