-javaagent:

当您需要从JVM内收集数据时,您会发现自己很危险地接近Java虚拟机内部进行工作。 幸运的是,有一些方法可以避免被JVM实现细节所困扰。 Java之父不仅给您提供了两个漂亮的工具供您使用。

在这篇文章中,我们将解释两种方法之间的差异,并解释为什么我们最近移植了算法的重要部分。

Java代理

第一种选择是使用java.lang.instrument接口。 这种方法使用-javaagent启动参数将监视代码加载到JVM本身。 作为Java的全部选择,如果您的背景是Java开发,那么javaagents往往是首选的方法。 说明您如何从该方法中受益的最佳方法是通过示例。

让我们创建一个真正简单的代理,该代理将负责监视代码中的所有方法调用。 当代理面对方法调用时,它将把调用记录到标准输出流中:

import org.objectweb.asm.*;public class MethodVisitorNotifyOnMethodEntry extends MethodVisitor {public MethodVisitorNotifyOnMethodEntry(MethodVisitor mv) {super(Opcodes.ASM4, mv);mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(MethodVisitorNotifyOnMethodEntry.class), "callback", "()V");}public static void callback() {System.out.println("Method called!");    }
}

您可以使用上面的示例,将其打包为javaagent(本质上是带有特殊MANIFEST.MF的小JAR文件),然后使用类似于以下内容的代理的premain()方法启动它:

java -javaagent:path-to/your-agent.jar com.yourcompany.YourClass

启动后,您会看到一堆“方法调用!” 日志文件中的消息。 就我们而言,仅此而已。 但是这个概念很强大,尤其是与上面的示例中的字节码检测工具(例如ASM或cgLib)结合使用时。

为了使示例易于理解,我们跳过了一些细节。 但这是相对简单的-使用java.lang.instrument包时,您首先编写自己的代理类,并实现public static void premain(String agentArgs,Instrumentation inst) 。 然后,您需要向inst.addTransformer注册您的ClassTransformer 。 由于您很可能希望避免对类字节码的直接操作,因此可以使用一些字节码操作库,例如我们使用的示例中的ASM。 有了它,您只需要实现几个接口– ClassVisitor (为简便起见,略过)和MethodVisitor。

JVMTI

第二种方法最终将带您进入JVMTI。 JVM工具接口( JVM TI )是标准的本机API,允许本机库捕获事件并控制Java虚拟机。 对JVMTI的访问通常打包在称为代理的特定库中。

下面的示例演示了与javaagent部分相同的回调注册,但是这次将其实现为JVMTI调用:

void JNICALL notifyOnMethodEntry(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method) {fputs("method was called!\n", stdout);
}int prepareNotifyOnMethodEntry(jvmtiEnv *jvmti) {jvmtiError error;jvmtiCapabilities requestedCapabilities, potentialCapabilities;memset(&requestedCapabilities, 0, sizeof(requestedCapabilities));if((error = (*jvmti)->GetPotentialCapabilities(jvmti, &potentialCapabilities)) != JVMTI_ERROR_NONE) return 0;if(potentialCapabilities.can_generate_method_entry_events) {requestedCapabilities.can_generate_method_entry_events = 1;}else {//not possible on this JVMreturn 0;}if((error = (*jvmti)->AddCapabilities(jvmti, &requestedCapabilities)) != JVMTI_ERROR_NONE) return 0;jvmtiEventCallbacks callbacks;memset(&callbacks, 0, sizeof(callbacks));callbacks.MethodEntry = notifyOnMethodEntry;if((error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks))) != JVMTI_ERROR_NONE) return 0;if((error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,    JVMTI_EVENT_METHOD_ENTRY, (jthread)NULL)) != JVMTI_ERROR_NONE) return 0;return 1;
}

两种方法之间存在一些差异。 例如,通过JVMTI,您可以获得比代理更多的信息。 但是,两者之间最关键的区别在于加载机制。 在将Instrumentation代理加载到堆内部时,它们由相同的JVM管理。 JVMTI代理不受JVM规则支配,因此不受JVM内部组件(如GC或运行时错误处理)的影响。 这意味着什么,最好通过我们自己的经验来解释。

从-javaagent迁移到JVMTI

三年前,当我们开始构建内存泄漏检测器时,我们并没有过多地关注这些方法的优缺点。 我们毫不犹豫地将解决方案实现为-javaagent

多年来,我们已经开始理解含义。 其中一些不太令人满意,因此在我们的最新版本中,我们将内存泄漏检测机制的重要部分移植到了本机代码。 是什么使我们跳到这样的结论?

首先-当驻留在堆中时,您需要将自己容纳在应用程序自己的内存结构旁边。 通过痛苦的经验中学到的东西本身就可能导致问题。 当您的应用程序已将堆填满到最大程度时,您最后需要做的是一个内存泄漏检测器,它似乎只会加快OutOfMemoryError的到达速度。

但是增加的堆空间减少了困扰我们的弊端。 真正的问题与以下事实有关:我们的数据结构是使用与受监视的应用程序本身正在使用的相同的垃圾收集器清理的。 这导致更长或更频繁的GC暂停。

尽管大多数应用程序不介意我们增加堆消耗的几个额外百分点,但我们了解到,需要消除对Full GC暂停产生的不可预测的影响。

更糟的是, Plumbr的工作方式是监视所有对象的创建和集合。 监视某物时,您需要保持跟踪。 跟踪往往会创建对象。 创建的对象将有资格使用GC。 现在,当您监视的是GC时,您刚刚创建了一个恶性循环-收集到更多的对象的垃圾,创建的监视器越多,触发的GC运行频率越高,等等。

跟踪对象时,JVMTI会通知我们有关对象死亡的信息。 但是,JVMTI不允许在这些回调期间使用JNI。 因此,如果我们使用Java保留有关跟踪对象的统计信息,则当我们收到更改通知时,不可能立即更新统计信息。 相反,当我们知道JVM处于正确状态时,需要将更改缓存并应用。 这造成了不必要的复杂性和更新实际统计数据的延迟。

翻译自: https://www.javacodegeeks.com/2014/03/migrating-from-javaagent-to-jvmti-our-experience.html

-javaagent:

-javaagent:_从javaagent迁移到JVMTI:我们的经验相关推荐

  1. jvmti_从javaagent迁移到JVMTI:我们的经验

    jvmti 当您需要从JVM内收集数据时,您会发现自己很危险地接近Java虚拟机内部进行工作. 幸运的是,有一些方法可以避免被JVM实现细节所困扰. Java之父没有给您提供过两个漂亮的工具供您使用. ...

  2. 从javaagent迁移到JVMTI:我们的经验

    当您需要从JVM内部收集数据时,您会发现自己很危险地接近Java虚拟机内部进行工作. 幸运的是,有一些方法可以避免被JVM实现细节所困扰. Java之父没有给您提供过两个漂亮的工具供您使用. 在这篇文 ...

  3. 划痕实验 迁移面积自动统计_从Jupyter迁移到合作实验室

    划痕实验 迁移面积自动统计 If you want to use Google Colaboratory to perform your data analysis, for building dat ...

  4. 数据迁移测试_自动化数据迁移测试

    数据迁移测试 Data migrations are notoriously difficult to test. They take a long time to run on large data ...

  5. 图像迁移风格保存模型_图像风格迁移

    样式迁移 如果你是一位摄影爱好者,也许接触过滤镜.它能改变照片的颜色样式,从而使风景照更加锐利或者令人像更加美白.但一个滤镜通常只能改变照片的某个方面.如果要照片达到理想中的样式,经常需要尝试大量不同 ...

  6. ruby json转化成对象_系统架构迁移实例:从Ruby到Rust

    前几年随着RoR(Ruby on Rails)框架的流行,很多初创企业选择Ruby和Rails作为基础开发框架,构建和快速迭代了其业务系统.但是随着业务规模的不断壮大,性能问题成了一个突出的问题,所以 ...

  7. date oracle 表中_从 MySQL 迁移数据到 Oracle 中的全过程

    一.前言 这里记录一次将MySQL数据库中的表数据迁移到Oracle数据库中的全过程 ,使用工具 Navicat,版本 12.0.11 操作环境及所用工具: mysql5.7 oracle18c wi ...

  8. 开发log4j配置_从 log4j 迁移到 logback

    最近把项目的日志框架从 log4j 迁移到 logback,过程里遇到很多坑,记录下来 目标 本次迁移的目标就是用 slf4j+logback 的日志框架来取代目前的 slf4j+log4j 如何迁移 ...

  9. dts数据库迁移工具_传统数据库迁移上云利器-ADAM

    自1970年关系型数据库被提出以来,至今已有50年历史.但在关系型数据库领域正在发生着巨大的变化,首先是互联网的发展,使得开源数据库越来越受欢迎,可扩展性成为支撑业务发展的重要特性,比如WebScal ...

最新文章

  1. Android 应用进行性能分析/APP/系统性能分析
  2. 使用jQuery将表单数据转换为JavaScript对象
  3. opencv findContours 崩溃CrtDbgBreak
  4. python集合属性方法运算_Python基础__字典、集合、运算符
  5. java爬虫下载付费html网页模板
  6. F5金飞:“双十一”安全事项三部曲
  7. zend studio 5出来了
  8. java整数翻转_java实现整数反转
  9. SAP Spartacus org unit页面的三种focus border及细节讨论
  10. OPA 7 - opaTest
  11. C/C++求一个整数的二进制中1的个数(用三种效率不同的方法实现)
  12. KPN iTV的敏捷转型之旅
  13. [转]numpy 100道练习题
  14. ExtJs视频教程下载地址
  15. 微信投票刷票器手机免费版、手机微信投票作弊神器原理
  16. MAC抓包工具charles(青花瓷)
  17. wireshark数据包分析 中职网络安全
  18. html网页在线加密解密工具源码
  19. Hi3516EV200设置手动曝光时间
  20. Package | 解决 Could not build wheels for opencv-python which use PEP 517 and cannot be installed

热门文章

  1. codeforces1553 F. Pairwise Modulo(数学)
  2. Codeforces Round #654 (Div. 2)
  3. 2018陕西省赛K题[watermelon_planting]
  4. SpringCloud Greenwich(四)注册中心之eureka、Zuul和 gateway网关配置
  5. 浅析SAX,DOM,JAXP,JDOM与DOM4J之间的关系
  6. 数据库连接池的选择及其开发配置
  7. 递归算法介绍及Java应用实战
  8. Java NIO总结
  9. EL表达式和Jstl常见的用法
  10. blog项目中遇到的问题及解决