【问题标题】:Faster alternative to get tags for objects than JVMTI GetTag获取对象标签的速度比 JVMTI GetTag 更快
【发布时间】:2018-11-14 23:10:15
【问题描述】:

当使用异步分析器和 gperftools 进行分析时,我注意到 jvmti->GetTag 在我的代理的结果中显示了很多。当我检查它是如何实现的时,我在jvmitTagMap.cpp的源代码中发现了以下内容:

jlong JvmtiTagMap::get_tag(jobject object) {
  MutexLocker ml(lock());

  // resolve the object
  oop o = JNIHandles::resolve_non_null(object);

  // for Classes get the tag from the klassOop
  return tag_for(this, klassOop_if_java_lang_Class(o));
}
  1. 虽然我的测试只有一个真正处于负载下的线程,但一旦我添加更多线程并大量使用GetTag,这似乎会更小。

我想使用标签为某些对象分配一个 id 并在我的 jvmti 代理中使用它。有什么想法可以更快地实现这一目标吗?与对象标题混淆不是一种选择(据我所知)。

注意:大多数事情应该在 C 端完成,因为我不希望我的 Java 代理以任何方式干扰应用程序。所谓干扰,我什至是指改变某些中心对象/类的内部状态(例如java.lang.StringCoding),或导致某些类被加载等

GetTag 已经在当前的 JVMTI 代理中大量使用,因此我正在寻找一种更快的方法来获取标签或实现我自己的机制,同时保持在 C 端。

【问题讨论】:

  • IdentityHashMap 怎么样?这个问题其实太宽泛了。这取决于您为什么需要 ID 以及如何使用它。
  • 好点,更新了问题。简而言之:我需要 C 端的 id 而不会弄乱 Java 中发生的任何事情。实际上现在我考虑了一下......因为我只需要一个在生命周期内不会改变的对象的唯一标识符,我不应该能够获得oop 并直接将其用作键吗?所以get_tag的做法是一样的。
  • 当您使用 C 语言处理 Java 对象时,您基本上会受到 JNI 和 JVMTI 函数的限制。他们确实有不可避免的开销。恐怕没有其他合法的方法可以从本地代理访问 Java 对象。特别是,处理裸oop 是非法的——这只是一个原始指针,可能随时变得无效,因为对象可以移动。
  • 我知道它不是公共 API,但仍然想知道引擎盖下发生了什么。从我今天看到的情况来看,jobject 似乎只转换为 oop*,然后被取消引用,然后转换为 ùnsigned int` 以用作标签映射中的哈希。但我一定在这里遗漏了一些东西。当对象不断在内存中移动时,oop如何成为映射中的键?如果我理解正确,oop 指向对象头,但对象可以被 GC 移动。我认为地图中的键不会在对象移动时一直更新,对吧?
  • JVM 知道 JvmtiTagMap 并在移动对象时更新它,请参阅JvmtiTagMap::do_weak_oops。当 JVM 处理指向 Java 堆的原始指针时,即oops,它要么确保两者之间不会发生 GC,要么将 oops 包装到句柄中。 jobject 就是这种 oop 句柄的一个例子。

标签: java performance jvm jvm-hotspot jvmti


【解决方案1】:

当您使用 C 语言处理 Java 对象时,您基本上会受到 JNI 和 JVMTI 函数的限制。而且它们确实有不可避免的开销。

恐怕没有其他合法的方法可以从本地代理访问 Java 对象。特别是,处理裸 oop 是非法的——这只是一个原始指针,可能随时变得无效,因为对象可以移动。

但是,JVM 可以使用 oops,甚至可以使用对象地址作为 JvmtiTagMap 中的键,只要它在移动对象时更新相应的 oops。而 HotSpot JVM 确实做到了这一点,请参阅 JvmtiTagMap::do_weak_oops

【讨论】:

  • 仔细想想,JVM 知道地图是有道理的。最后,一旦对象被 gc'ed,还需要进行清理。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多