在前面的介绍中,我们看到JVM TI的强大功能,然而,对于不熟悉C/C++语言的Java程序员来说,这扇门是不是真的就完全关闭了呢?还好,在关上了门的同时,JVM为我们提供了另一扇窗——Java Instrutment。其实Java Instrutment只提供了JVM TI中非常小的一个功能子集,一个是允许在类加载之前,修改类字节(ClassFileTransformer)(JDK5中开始提供,即使随JVM启动的Agent),另外一个是在类加载之后,触发JVM重新进行类加载(JDK6中开始提供,用于JVM启动之后通过Attach去加载Agent)。这两个功能表面看起来微不足道,但实际非常强大,AspectJ AOP的动态Weaving、Visual VM的性能剖析、JConsole支持Attach到进程上进行监控,都是通过这种方式来做的。除了这两个功能外,JDK 6中还提供了动态增加BootstrapClassLoader/SystemClassLoader的搜索路径、对Native方法进行instrutment(还记得JVM TI的Native Method Bind吗?)。
1.主要API(java.lang.instrutment)
1)ClassFileTransformer:定义了类加载前的预处理类,可以在这个类中对要加载的类的字节码做一些处理,譬如进行字节码增强
2)Instrutmentation:增强器,由JVM在入口参数中传递给我们,提供了如下的功能
- addTransformer/ removeTransformer:注册/删除ClassFileTransformer
- retransformClasses:对于已经加载的类重新进行转换处理,即会触发重新加载类定义,需要注意的是,新加载的类不能修改旧有的类声明,譬如不能增加属性、不能修改方法声明
- redefineClasses:与如上类似,但不是重新进行转换处理,而是直接把处理结果(bytecode)直接给JVM
- getAllLoadedClasses:获得当前已经加载的Class,可配合retransformClasses使用
- getInitiatedClasses:获得由某个特定的ClassLoader加载的类定义
- getObjectSize:获得一个对象占用的空间,包括其引用的对象
- appendToBootstrapClassLoaderSearch/appendToSystemClassLoaderSearch:增加BootstrapClassLoader/SystemClassLoader的搜索路径
- isNativeMethodPrefixSupported/setNativeMethodPrefix:支持拦截Native Method
我们后面通过范例来了解如何使用Java Instrutment技术。
2.随JVM启动的Agent
1)定义入口
public class StubPreMain
{
//另外一种入口格式是public static void premain(String agentArgs)
public static void premain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException
{
inst.addTransformer(new StubTransformer());
System.out.println("StubPreMain:Add StubTransformer");
}
}
我们的入口类格式必须是如上的premain(对应JVM TI的Agent_OnLoad方法),与JVM TI类似,JVM启动的时候回回调这个入口函数。在premain中我们最常见就是增加Transform,Transform允许我们在类加载器修改bytecode。一般性能剖析程序都是通过修改字节码,在方法进入和退出时收集时间数据来得出剖析数据的。
2)编写Transform
public class StubTransformer implements ClassFileTransformer
{
/*
* (non-Javadoc)
*
* @see java.lang.instrument.ClassFileTransformer#transform(java.lang.ClassLoader,
* java.lang.String, java.lang.Class, java.security.ProtectionDomain,
* byte[])
*/
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException
{
if ("ray.WebStub".equals(className))
{
System.out.println("Load WebStub From Transformer");
return readByte("WebStub.classbyte");
}
return null;
}
public byte[] readByte(String fileName)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = StubTransformer.class
.getResourceAsStream(fileName);
int BUFFER_SIZE = 1024;
byte[] buffer = new byte[BUFFER_SIZE];
int length = BUFFER_SIZE;
while (length == BUFFER_SIZE)
{
try
{
length = is.read(buffer);
baos.write(buffer, 0, length);
} catch (IOException e)
{
e.printStackTrace();
}
}
return baos.toByteArray();
}
}
这里简单地使用一个编译好的新的class的字节替换掉旧的class的字节,实际中我们当然不会使用这么苯的方法,实际上有各种字节码操作工具可以辅助我们完成这个任务
3)修改META-INF/ MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: ray.StubPreMain
4)打成stubagent.jar,在启动参数中增加如下启动参数,启动JVM,当加载ray.WebStub这个类的时候,字节码会变成我们传进去的新的字节码
-javaagent:D:/Workspace/agent/stubagent.jar
3.通过Attach在JVM运行期间加载的Agent
这种Agent是JDK6才开始支持的,因此使用一般还是比较少的,我们来看一个实际使用范例,在前面的JVM Management API
的介绍中,我们知道,通过Attach API连接到JVM上,然后加载management-agent.jar,就可以在JVM中启动一个JMX代理。实际上management-agent.jar是一个支持通过Attach在JVM运行期间加载的Agent。management-agent.jar实际上只有一个META-INF/ MANIFEST.MF文件,内容如下:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Agent-Class: sun.management.Agent
Premain-Class: sun.management.Agent
可以看出这个包实际上既支持随JVM一起启动(我们前面看到的Premain-Class配置),也支持在JVM启动后通过Attach API去加载启动(看Agent-Class配置),我们通过反汇编看看sun.management.Agent是怎么做的。
sun.management.Agent定义了入口函数agentmain(对应于Agent_OnAttach方法)
public class Agent
{
public static void premain(String agentArgs)
throws Exception
{
agentmain(s);
}
public static void agentmain(String agentArgs)
throws Exception
{
….
}
}
与Premian-Agetn类似,另外一种入口函数格式是public static void premain(String agentArgs, Instrumentation inst)。
分享到:
相关推荐
JPDA(Java Platform Debugger Architecture)是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。 JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),...
JPDA(Java Platform Debugger Architecture)是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。 JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),...
使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试
基于JPDA的Java软件性能测试.pdf
文档内详细介绍了java的调试体系--JPDA,包括其接口,以及一些与虚拟机相关的知识
多目标跟踪JPDA算法实现,是学习JPDA算法的经典代码,建议下载下来看看。
Tool APIs java javac javadoc jar javap JPDA JConsole Java VisualVM Java DB Security Int'l RMI IDL Deploy Monitoring Troubleshoot Scripting JVM TI JRE RIAs Java Web Start Applet / Java Plug-in ...
JPDA(JavaPlatformDebuggerArchitecture)是Java平台调试体系结构的缩写,通过JPDA提供的API,开发人员可以方便灵活的搭建Java调试应用程序。JPDA主要由三个部分组成:Java虚拟机工具接口(JVMTI),Java调试线协议...
采用JPDA数据关联算法实现两个个匀速运动目标的点迹与航迹的关联。上传的为压缩文件,解压后有两个m文件,一个是Data_JPDAF.m,另一个是JPDAF.m。将两个文件放到Matlab的同一个目录下,直接运行文件Data_JPDAF.m即可...
联合概率数据互联JPDA是数据关联算法之一,它的基本思想是:对应于观测数据落入跟踪门相交区域的情况,这些观测数据可能来源于多个目标。JPDA的目的在于计算观测数据与每一个目标之间的关联概率,且认为所有的有效...
matlab简单实现多目标跟踪的JPDA算法,供初学者参考
采用JPDA数据关联算法实现两个匀速运动目标的点迹与航迹的关联
数据关联的JPDA算法 程序运行正常 注释详尽
能实现多目标跟踪中数据关联,对每个目标设置合适的跟踪门,在跟踪门内认为增加杂波产生数据
数据关联的经典算法JPDA,包含杂波环境。
Adaptation (JPDA) approach, to replace the frequently-used joint maximum mean discrepancy metric in transfer learning. During the distribution adaptation, JPDA improves the transferability between ...
JPDA的matlab程序.pdf