How does the Garbage Collector update the references pushed to the operand stack?

Deadly 提交于 2021-02-08 03:36:11

问题


The JVM can easily update the references of local variables, static references, class instances or object array instances when moving an object in heap. But how can it update the references pushed to the operand stack?


回答1:


There is no fundamental difference between a local variable and an entry in the operand stack. Both live in the same stack frame. Neither is formally declared and both need the JVM to perform inference to recognize their actual use.

The following code

public static void example() {
    {
        int foo = 42;
    }
    {
        Object bar = "text";
    }
    {
        long x = 100L;
    }
    {
        Object foo, bar = new Object();
    }
}

will (typically) get compiled to

  public static void example();
    Code:
       0: bipush        42
       2: istore_0
       3: ldc           #1                  // String text
       5: astore_0
       6: ldc2_w        #2                  // long 100l
       9: lstore_0
      10: new           #4                  // class java/lang/Object
      13: dup
      14: invokespecial #5                  // Method java/lang/Object."<init>":()V
      17: astore_1
      18: return

Note how the local variable at index 0 in the stack frame gets reassigned with values of different types. As a bonus, the last store to variable index 1 invalidates the variable at index 0 as it otherwise would contain a dangling half of a long value.

There are no additional hints about the type of local variables, debugging information is optional and stack map tables are only there when the code contains branches.

The only way to determine whether a local variable contains a reference, is to follow the program flow and retrace the effect of the instructions. This does already imply inferring the values on the operand stack, as without it, we wouldn’t even know what the store instruction put into the variable.

The verifier does it, it’s even mandatory, and the garbage collector or whatever supporting code of the JVM can do it too. An implementation may even have a single analyzing code keeping the type information of the first analysis, which would be the verification.

But even when this information is reconstructed every time the garbage collector needs it, the overhead would not be astronomical. The garbage collector runs only periodically and it only needs this information for the currently executed methods. And that’s all about interpreted execution only.

When the JIT compiler generates code, it needs to utilize the type information anyway and can prepare information for the garbage collector, but it will do so only for certain points called safepoints where the generated code checks whether there’s an outstanding garbage collection. This implies that in-between these points, the data doesn’t need to be in a form the garbage collector understands and the optimized code may assume that the garbage collector won’t relocate objects while it is processing them.

It also implies that in compiled, optimized code the reachability might be entirely different than in simple interpreted execution, i.e. unused variables might be absent, but even objects in use from a source code point of view may be considered unused when the optimized code works with copies of their fields, e.g. in CPU registers.



来源:https://stackoverflow.com/questions/60511540/how-does-the-garbage-collector-update-the-references-pushed-to-the-operand-stack

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!