OpenJDK跟踪ReentrantLock加锁与解锁

问题描述 投票:0回答:1

我正在使用解释器进行运行时检测。 我现在的重点是在任何

ReEntractLock
lock()
unlock()
函数之前添加函数调用。

作为参考,这是 Test.java:

class Test {
    static Lock lock = new ReentrantLock();
    public String name;

    public Test(String name) {
        this.name = name;
    }

    public void test() {
        lock.lock();
        try {
            System.out.println("Hello " + name);
            name = "World";
        } finally {
            lock.unlock();
        }
    }

} 

通过检查字节码,我发现每次锁定/解锁时,都有一个

invokeinterafce
字节码。

public void test();
   Code:
       0: getstatic     #13                 // Field lock:Ljava/util/concurrent/locks/Lock;
       3: invokeinterface #17,  1           // InterfaceMethod java/util/concurrent/locks/Lock.lock:()V
       8: ...
      26: getstatic     #13                 // Field lock:Ljava/util/concurrent/locks/Lock;
      29: invokeinterface #23,  1           // InterfaceMethod java/util/concurrent/locks/Lock.unlock:()V
      34: ...

所以我进入

src/hotspot/cpu/x86/templateTable_x86.cpp
,并添加了一个 vm leaf 调用。

void TemplateTable::invokeinterface(int byte_no) {
...
// rbx: Method* to call
  // rcx: receiver
  // Check for abstract method error
  // Note: This should be done more efficiently via a throw_abstract_method_error
  //       interpreter entry point and a conditional jump to it in case of a null
  //       method.
  __ testptr(rbx, rbx);
  __ jcc(Assembler::zero, no_such_method);

  __ profile_arguments_type(rdx, rbx, rbcp, true);

  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::monitor_invoke), rbx); // <- the call, rbx contains the method pointer
  ...
}

但是,这样我就得到了调用接口调用的每个方法,而I能想到的唯一方法就是检查名称,就像这样

if (strstr(name, "java.util.concurrent.locks.ReentrantLock"))...

然而,这看起来很糟糕,并且可能会增加太多额外的开销。

是否有其他方法可以跟踪

lock/unlock
拨打的
java.util.concurrent
电话或者更便宜的方法来进行姓名比较?

java jvm interpreter instrumentation jvm-hotspot
1个回答
0
投票

检测

invokeinterface
还不够。如果
lock
字段使用
ReentrantLock
类型声明,则将使用
lock.lock()
而不是
invokevirtual
来调用
invokeinterface

好消息是您不需要更改 VM 源来跟踪方法调用。有一个用于此类事物的标准 API,称为“JVM 工具接口”(JVM TI)。您所需要做的就是创建一个代理,为 MethodEntryMethodExit 事件安装回调。您可以在这个答案中找到使用这些事件的示例。 如文档中所述,启用 MethodEntry/MethodExit 事件可能会显着降低性能。要以更高效的方式拦截对

ReentrantLock.lock

/

unlock
方法的调用,请考虑使用
字节码检测
。这个想法是在运行时动态更改 lock/
unlock
方法的实现,插入字节码来调用监控函数。此类检测方法可以受益于 JIT 编译和所有 JVM 优化。
    

© www.soinside.com 2019 - 2024. All rights reserved.