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

当您需要从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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML--HTML对象的关于位置和大小的属性的图解

转载于:https://www.cnblogs.com/duadu/archive/2007/08/08/6166687.html

flower.php,flower.php

session_start();//定义个常量,用来授权调用includes里面的文件define(IN_TG,flower);define(IN_JS,flower);//定义个常量,用来指定本页的内容define(SCRIPT,message);//引入公共文件require dirname(__FILE__)./includes/common.inc.php;//判断是否登录…

BABOK - 需求管理和沟通(Requirements Management and Communication)概要

本文更新版本已挪至 http://www.zhoujingen.cn/itbang/345.html ------------------------------------------- 描述 需求管理和沟通描述我们如何管理冲突、问题、变更,并确保涉众和项目团队在方案范围内保持一致。不同项目的复杂度和方法论支持都不一样&#xff0c…

Java 8的默认方法:可以做什么和不能做什么?

什么是默认方法 在Java 8发行版中,您可以修改接口以添加新方法,以便该接口与实现该接口的类保持兼容。 如果您要开发一个库,该库将由基辅到纽约的几位程序员使用,那么这非常重要。 在Java 8出现之前,如果您在库中发布了…

P1047 校门外的树

P1047 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,…,L,都种有一棵…

.Net Core Swagger:Actions require an explicit HttpMethod binding for Swagger 2.0

添加完Swagger包引用后运行报错:Actions require an explicit HttpMethod binding for Swagger 2.0 第一时间想到了父类控制器 没有添加 [HttpPost] 之类的特性 添加后就可以解决这个报错原因 但是我的父类控制器里的两个方法只是为了做返回值的一些处理&#xff0c…

matlab impdt,实验1 基于Matlab的数字信号处理基本操作

图1-7 离散时间信号的基本运算及波形图>>title(x2(n)),axis([-15 15 0 1]) >>subplot(413)>>stem(n3,x,fill),grid on >>title(x3(n)),axis([-15 15 0 1]) >>subplot(414)>>stem(n4,x,fill),grid on >>title(x4(n)),axis([-15 15 0 …

画函数图形的C#程序(改进版) (转)

我在10月份发表过一篇随笔“画函数图形的C#程序,兼论一个病态函数”,在那篇随笔中写道: 这个画函数图形的C#程序有一个严重的缺点,就是函数表达式是直接写的源程序中的,不能象SciLab和Matlab那样交互式地输入。 后来&a…

Swift-UITextView占位文字及占位文字颜色扩展(可在xib中直接使用)

使用案例 extension UITextView {private struct RuntimeKey {static let hw_placeholderLabelKey UnsafeRawPointer.init(bitPattern: "hw_placeholderLabelKey".hashValue)/// ...其他Key声明}/// 占位文字IBInspectable public var placeholder: String {get {re…

Java 8中Lambda表达式的阴暗面

这篇文章可能不会使我成为任何新朋友。 哦,好吧,无论如何我从来没有真正在学校受到欢迎。 但是,让我们说清楚。 就语言而言,Java 8的最大特色无疑是Lambda表达式。 几年来,它一直是功能语言(例如Scala和Clo…

JQ实现弹幕效果

JQ实现弹幕效果&#xff0c;快来吐糟你的想法吧 效果图&#xff1a; 代码如下&#xff0c;复制即可使用&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>JQ实现弹幕效果</title><style type"t…

获取表的所有列名

selectname fromsyscolumns whereidobject_id(表名)下面这样也可以:selectcolumn_name frominformation_schema.columns wheretable_name news转载于:https://www.cnblogs.com/zhuboxingzbx/archive/2007/09/03/880049.html

天下武功唯快不破------实验吧

题目地址&#xff1a;http://www.shiyanbar.com/ctf/1854 打开链接 全是英文&#xff0c;能力有限&#xff0c;翻译一下&#xff0c;好像没其他东西了&#xff0c;查看一下源码 让用post请求&#xff0c;丢到burp改一下 看到response有一个FLAG: UDBTVF9USElTX1QwX0NINE5HRV9GT…

JS实现文本中查找并替换字符

JS实现文本中查找并替换字符 效果图&#xff1a; 代码如下&#xff0c;复制即可使用&#xff1a; <!DOCTYPE html><html> <head><style type"text/css">*{font-family:"微软雅黑";font-size:16px;margin:0;padding:0;letter-spaci…

在没有IDE的情况下编译和运行Java

最近一个名为“ 不使用IDE编译Java软件包 ”的Java subreddit线程提出了一个问题&#xff1a;“是否有一个命令将软件包内的一组Java文件编译到一个单独的文件夹中&#xff08;以下简称为bin&#xff09;&#xff0c;以及如何我会去运行新的类文件吗&#xff1f;” 该帖子的作者…

[转]MySQL 表锁和行锁机制

本文转自&#xff1a;http://www.cnblogs.com/itdragon/p/8194622.html MySQL 表锁和行锁机制 行锁变表锁&#xff0c;是福还是坑&#xff1f;如果你不清楚MySQL加锁的原理&#xff0c;你会被它整的很惨&#xff01;不知坑在何方&#xff1f;没事&#xff0c;我来给你们标记几个…

使用JS实现文字搬运工

使用JS实现文字搬运工 效果图&#xff1a; 代码如下&#xff0c;复制即可使用&#xff1a; <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <title>使用JS实现文字搬运工&…

ActiveMQ –经纪人网络解释–第3部分

现在&#xff0c;我们已经在本博客系列的第1部分和第2 部分中了解了ActiveMQ网络连接器的基础&#xff0c;在第3部分中&#xff0c;我们将研究ActiveMQ如何平衡连接到代理网络的使用者。 介绍 当可以无序处理队列中的消息时通常使用并发使用者&#xff0c;通常可以提高消息吞吐…

Linux下用户组、文件权限详解=------转载文

转载自-----原文地址&#xff1a; https://www.cnblogs.com/123-/p/4189072.html Linux下用户组、文件权限详解 用户组 在linux中的每个用户必须属于一个组&#xff0c;不能独立于组外。在linux中每个文件有所有者、所在组、其它组的概念 - 所有者 - 所在组 - 其它组 - 改变用…

JS实现逼真的雪花飘落特效

逼真的雪花飘落特效 效果图&#xff1a; 图片素材 &#xff1a; --> ParticleSmoke.png 代码如下&#xff0c;复制即可使用&#xff1a; <!doctype html> <html> <head> <meta charset"UTF-8"> <meta name"renderer" conte…