Java Attach API

catalog

1. instrucment与Attach API
2. BTrace: VM Attach的两种方式
3. Sun JVM Attach API

 

1. instrucment与Attach API

JDK5中增加了一个包java.lang.instrucment,能够对JVM底层组件进行访问。在JDK 5中,Instrument 要求在运行前利用命令行参数或者系统参数来设置代理类,在实际的运行之中,虚拟机在初始化之时(在绝大多数的 Java 类库被载入之前),instrumentation的设置已经启动,并在虚拟机中设置了回调函数,检测特定类的加载情况,并完成实际工作
​在Java5中,开发基于Instrucment的应用,需要以下几个步骤

1. 编写premain函数
​2. jar文件打包
​3. 运行agent 

但是在实际的很多的情况下,我们没有办法在虚拟机启动之时就为其设定代理,这样实际上限制了instrument的应用。而Java SE 6的新特性改变了这种情况,通过Java Tool API中的attach方式,我们可以很方便地在运行过程中动态地设置加载代理类,以达到instrumentation的目的
​在JDK6中,针对这点做了改进,开发者可以在main开始执行以后,再开启自己的Instrucment程序
Attach API不是Java的标准API,而是Sun公司提供的一套扩展API,用来向目标JVM"附着"(Attach)代理工具程序的。有了它,开发者可以方便的监控一个JVM,运行一个外加的代理程序,Sun JVM Attach API功能上非常简单,仅提供了如下几个功能

1. 列出当前所有的JVM实例描述
2. Attach到其中一个JVM上,建立通信管道
3. 让目标JVM加载Agent

Relevant Link:

http://iamzhongyong.iteye.com/blog/1843558

 

2. BTrace: VM Attach的两种方式

BTrace的特点之一就是可以动态Attach到一个运行的JVM进程上,然后根据BTrace脚本来对目标JVM进行相应的操作
JVM的 Attach有两种方式

1. 指定javaagent参数
2. 运行时动态attach

0x1: 指定javaagent参数

这种方式的特点就是在目标JVM启动时,就确定好了要加载什么样的代理对象,例如

java -javaagent:xxxx.jar TestMain

TestMain.java

package test;public class TestMain 
{ public static void main(String[] args) throws InterruptedException{System.out.println("Hello");}}

TestAgent.java

package test;import java.lang.instrument.Instrumentation;
import java.io.*;public class TestMain 
{ public static void agentmain(String args, Instrumentation inst) throws Exception {System.out.println("Args:" + args);}public static void premain(String args, Instrumentation inst) throws Exception {System.out.println("Pre Args:" + args);Class[] classes = inst.getAllLoadedClasses();for (Class clazz : classes) {System.out.println(clazz.getName());}} 
}

TestAgent类比较简单,最终它会在目标类的Main方法执行之前,执行premain方法,其主要动作是将以及加载的类打印出来。 我们需要将这个类打包成jar文件,以便在目标JVM启动时候,以参数形式指定给它。打成jar的同时,设定MANIFEST.MF文件的内容。告知目标JVM该如何处理

Agent-Class: TestAgent
Premain-Class: TestAgent
Can-Redine-Classes: true
Can-Retransform-Classes: true

用jar命令将TestAgent打包

1. 编译TestAgent
javac TestAgent.java2. jar打包
jar cvmf MANIFEST.MF xxx.jar TestAgent.class

启动TestMain,并设置javaagent参数

1. 编译TestMain
javac TestMain.java 2. 启动TestMain
java -javaagent:xxx.jar TestMain

0x2: 动态Attach,load指定Agent

这种方式与之前指定参数的不同在于,其可以在JVM已经运行的情况下,动态的附着上去,并可以动态加载agent
TestMain.java

public class TestMain 
{public static void main(String[] args) throws InterruptedException {  while(true){  Thread.sleep(10000);  new Thread(new WaitThread()).start();  }  }  static class WaitThread implements Runnable {  @Override  public void run() {  System.out.println("Hello"); }       }  
}

TestAgent.java

import java.lang.instrument.Instrumentation;
import java.io.*;public class TestAgent
{ public static void agentmain(String args, Instrumentation inst) throws Exception {System.out.println("Args:" + args);}public static void premain(String args, Instrumentation inst) throws Exception {System.out.println("Pre Args:" + args);Class[] classes = inst.getAllLoadedClasses();for (Class clazz : classes) {System.out.println(clazz.getName());}} 
}

动态加载agent的情况下,被调用的是agentmain方法, 其会在JVMload的时候,被调用
MANIFEST.MF

Agent-Class: TestAgent
Premain-Class: TestAgent
Can-Redine-Classes: true
Can-Retransform-Classes: true

将类打包为jar包

1. 编译TestAgent
javac TestAgent.java2. jar打包
jar cvmf MANIFEST.MF xxx.jar TestAgent.class

动态附着到对应的JVM需要使用到JDK的Attach API
Main.java

import com.sun.tools.attach.VirtualMachine;public class Main 
{  public static void main(String[] args) throws Exception{  VirtualMachine vm = null;  String agentjarpath = "C:/Users/zhenghan.zh/Desktop/新建文件夹/xxx.jar"; //agentjar路径  vm = VirtualMachine.attach("9730");//目标JVM的进程ID(PID)  vm.loadAgent(agentjarpath, "This is Args to the Agent.");  vm.detach();  }  
}

一旦运行这个Main方法, 其就会动态的附着到我们对应的JVM进程中,并为目标JVM加载我们指定的Agent,以达到我们想做的事情, 比如BTrace就为在附着到目标JVM后,开启一个ServerSocket,以便达到与目标进程通讯的目的

Relevant Link:

http://ivanzhangwb.github.io/btrace-vm-attach-api/ 

 

3. Sun JVM Attach API

Sun JVM Attach API是Sun JVM中的一套非标准的可以连接到JVM上的API,从JDK6开始引入,除了Solaris平台的Sun JVM支持远程的Attach,在其他平台都只允许Attach到本地的JVM上

0x1: 列出当前所有的JVM实例描述

package test;
import java.util.List;import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;public class Test 
{public static void main(String[] args) {List<VirtualMachineDescriptor> list = VirtualMachine.list();  for (VirtualMachineDescriptor vmd : list)  {  System.out.println("pid:" + vmd.id() + ":" + vmd.displayName());  }  }}
//tools.jar needs to be added to the IDE's library path and the program's classpath. The tools.jar file is found in the JDK's lib directory.

0x2: Attach到特定进程的JVM上,并加载Agent

//Attach到JVM上
VirtualMachine virtualmachine = VirtualMachine.attach(pid);  
//加载Agent
String javaHome = virtualmachine.getSystemProperties().getProperty("java.home");  
String agentPath = javaHome + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar");  
File file = new File(agentPath);  
if(!file.exists())  
{  agentPath = javaHome + File.separator + "lib" + File.separator + "management-agent.jar";  file = new File(agentPath);  if(!file.exists())  throw new IOException("Management agent not found");  }  
}  agentPath = file.getCanonicalPath();  
try  
{  virtualmachine.loadAgent(agentPath, "com.sun.management.jmxremote");  
}  
catch(AgentLoadException e)  
{  throw new IOException(e);  
}  
catch(AgentInitializationException agentinitializationexception)  
{  throw new IOException(e);  
}  
Properties properties = virtualmachine.getAgentProperties();  
address = (String)properties.get("com.sun.management.jmxremote.localConnectorAddress");  
virtualmachine.detach(); 

0x3: Attach API底层实现(windows)

\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsAttachProvider.java

public VirtualMachine attachVirtualMachine(String vmid) throws AttachNotSupportedException, IOException
{checkAttachPermission();// AttachNotSupportedException will be thrown if the target VM can be determined// to be not attachable.
    testAttachable(vmid);return new WindowsVirtualMachine(this, vmid);
}

\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsVirtualMachine.java

WindowsVirtualMachine(AttachProvider provider, String id) throws AttachNotSupportedException, IOException
{//继承HotSpotVirtualMachine
    super(provider, id);int pid;try {pid = Integer.parseInt(id);} catch (NumberFormatException x) {throw new AttachNotSupportedException("Invalid process identifier");}//先连接上目标JVMhProcess = openProcess(pid);// The target VM might be a pre-6.0 VM so we enqueue a "null" command// which minimally tests that the enqueue function exists in the target// VM.try {enqueue(hProcess, stub, null, null);} catch (IOException x) {throw new AttachNotSupportedException(x.getMessage());}
}

WindowsVirtualMachine继承HotSpotVirtualMachine,先看看HotSpotVirtualMachine的loadAgent方法
\openjdk\jdk\src\share\classes\sun\tools\attach\HotSpotVirtualMachine.java

/*
* Load JPLIS agent which will load the agent JAR file and invoke
* the agentmain method.
*/
public void loadAgent(String agent, String options) throws AgentLoadException, AgentInitializationException, IOException
{String args = agent;if (options != null) {args = args + "=" + options;}try {loadAgentLibrary("instrument", args);} catch (AgentLoadException x) {throw new InternalError("instrument library is missing in target VM");} catch (AgentInitializationException x) {/** Translate interesting errors into the right exception and* message (FIXME: create a better interface to the instrument* implementation so this isn't necessary)*/int rc = x.returnValue();switch (rc) {case JNI_ENOMEM:throw new AgentLoadException("Insuffient memory");case ATTACH_ERROR_BADJAR:throw new AgentLoadException("Agent JAR not found or no Agent-Class attribute");case ATTACH_ERROR_NOTONCP:throw new AgentLoadException("Unable to add JAR file to system class path");case ATTACH_ERROR_STARTFAIL:throw new AgentInitializationException("Agent JAR loaded but agent failed to initialize");default :throw new AgentLoadException("Failed to load agent - unknown reason: " + rc);}}
}

loadAgentLibrary("instrument", args);

/*
* Load agent library
* If isAbsolute is true then the agent library is the absolute path
* to the library and thus will not be expanded in the target VM.
* if isAbsolute is false then the agent library is just a library
* name and it will be expended in the target VM.
*/
private void loadAgentLibrary(String agentLibrary, boolean isAbsolute, String options) throws AgentLoadException, AgentInitializationException, IOException
{InputStream in = execute("load",agentLibrary,isAbsolute ? "true" : "false",options);try {int result = readInt(in);if (result != 0) {throw new AgentInitializationException("Agent_OnAttach failed", result);}} finally {in.close();}
}

可以看到,Java在Attach到目标进行后,调用execute让目标进行加载Agent类,我们继续分析execute的实现方式,可以看到,JVM进程间通信是JVM Attach API的核心,JVM自身就预留了执行来自Attach进程的指令接口
\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsVirtualMachine.java

InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException
{assert args.length <= 3;        // includes null// create a pipe using a random nameint r = (new Random()).nextInt();String pipename = "\\\\.\\pipe\\javatool" + r;long hPipe = createPipe(pipename);// check if we are detached - in theory it's possible that detach is invoked// after this check but before we enqueue the command.if (hProcess == -1) {closePipe(hPipe);throw new IOException("Detached from target VM");}try {// enqueue the command to the process
        enqueue(hProcess, stub, cmd, pipename, args);// wait for command to complete - process will connect with the// completion status
        connectPipe(hPipe);// create an input stream for the pipePipedInputStream is = new PipedInputStream(hPipe);// read completion statusint status = readInt(is);if (status != 0) {// special case the load command so that the right exception is thrownif (cmd.equals("load")) {throw new AgentLoadException("Failed to load agent library");} else {throw new IOException("Command failed in target VM");}}// return the input streamreturn is;} catch (IOException ioe) {closePipe(hPipe);throw ioe;}
}

JVM的execute方法中调用了大量native方法,并且从代码中可以看出,JVM Attach的进程间通信使用了管道进行通信

Relevant Link:

http://ayufox.iteye.com/blog/655761 
http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html
http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/index.html 

 

Copyright (c) 2015 LittleHann All rights reserved

 

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

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

相关文章

TCP之三次握手和四次挥手过程

1 TCP包头里面的标志位 下图为TCP头部里面部分信息,入下标志位,每个标志位占一位。 标志位这里会涉及3个,ACK SYN FIN ACK:确认序号有效。 SYN:发起一个新连接。 FIN:释放一个连接。 2 三次握手过程 第一次握手 Client将标志位SYN置1,随机产生一个值seq=J,并将数…

Handler 机制分析

android 子线程和UI线程的交互主要使用Handler的方法进行通信。本文分析Handler机制 Handler 如何使用&#xff1f; Handler的使用比较简单 public class MainActivity extends Activity{private Handler handler new Handler() { public void handleMessage(Message msg) { …

gearman mysql编译_gearman初探(一、编译和安装)

gearman是一个任务分发系统&#xff0c;将计算比较耗时的任务分发给不同的机器专门进行计算&#xff0c;而任务发起的初始程序不必等待这些任务完成就可以返回而继 续执行。笔者最开始做PHP邮件发送的时候&#xff0c;因为邮件发送耗时比较长&#xff0c;这时PHP脚本就会被阻塞…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(四)了解魔法百宝箱列表、字典及基本数据类型

学习目标 了解魔法世界中可更改容器——变量了解魔法世界的基本数值类型——字符串、整数了解魔法百宝箱——字典、列表了解列表如何添加值了解字典如何添加值了解字典与列表定义的不同符号 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得懂的Python入门教程 》——&…

TCP协议之如何保证传输的可靠性

一、问题 TCP协议之如何保证传输的可靠性?我们先看下TCP的头部图片和TCP头部的字段 /*TCP头定义,共20个字节*/ typedef struct _TCP_HEADER {short m_sSourPort;       // 源端口号16bitshort m_sDestPort;       // 目的端口号16bitunsigned int …

【工具篇】在Mac上开发.Net Core需要的工具

微信公众号&#xff1a;趣编程ACE关注可了解更多的.NET日常开发技巧,如需帮助&#xff0c;请后台留言&#xff1b;[如果觉得本公众号对您有帮助&#xff0c;欢迎关注]在Mac上开发.Net Core需要的工具如果您是一个.NET 开发者&#xff0c;想从Windows切换到Mac上开发.NET或者您已…

【Pix4d精品教程】Pix4Dmapper完整航测内业操作流程手把手图文教程

1. 作业流程图 2. 原始资料准备 原始资料包括影像数据、POS数据以及控制点数据。 确认原始数据的完整性,检查获取的影像中有没有质量不合格的相片。同时查看POS数据文件,主要检查航带变化处的相片号,防止POS数据中的相片号与影像数据相片号不对应,出现不对应情况应手动调…

关于构造函数和this调用的思考

文中一系列思考和内容引发自以下问题&#xff1a;我需要在一个类的构造函数中调用另一个对象的构造函数&#xff0c;并使用this初始化其中的一个引用成员。 主要遇到的问题&#xff1a; 1. 构造函数的初始化列表中能访问this吗&#xff1f; 很明显c创建一个对象分为两部分&…

mysql semi join_MySQL 5.6 Semi join优化之materialization strategy

8月 24, 2014 |Nix.Huang考虑如下查询&#xff1a;select * from Countrywhere Country.code IN (select City.Countryfrom Citywhere City.Population > 7*1000*1000)and Country.continentEurope这个子查询是非相关子查询&#xff0c;我们能和外层循环独立的执行它&#x…

【ArcGIS风暴】何为动态投影?这次全面为您揭开ArcGIS中动态投影的神秘面纱!

本课程配套蓝光视频: 【ArcGIS风暴】GIS动态投影问题 GISer们都见过以下警告,该警告的原因是当前加载的数据的坐标系和当前数据框坐标系不一致导致的,核心问题是地理坐标系不一致。如当前数据的坐标系是GCS_Xian_1980,而数据框的坐标系有可能是WGS_1984等,总之跟要加载的数…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(五)我的魔法竟然有了一丝逻辑

学习目标 了解魔法世界中的结构表现——缩进了解魔法世界的逻辑判断——if了解魔法世界的多次逻辑判断——ifelse嵌套了解魔法世界中的逻辑运算——且 and 与或 or 推荐 1.《备受好评的看得懂的C语言入门教程》 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得懂的P…

类和类之间的关系

一、类和类之间的关系 UML类图中&#xff0c;常见以下几种关系: 1、泛化&#xff08;Generalization&#xff09; 是一种继承关系&#xff0c;比如动物类和老虎类&#xff0c;老虎继承动物&#xff0c;子类如何特化父类的所有特征和行为 箭头指向:带三角箭头的实线&#xff0…

Java SpringMvc+hibernate架构中,调用Oracle中的sp,传递数组参数

一、问题 我们调用数据&#xff0c;大都是可以直接获取表中的数据&#xff0c;或者用复杂点的sql语句组成的。但是&#xff0c;有时候&#xff0c;当这样达不到我们要的全部数据的时候&#xff0c;这时&#xff0c;我们就用到了存储过程【sp】&#xff0c;如果sp需要参数是数组…

js模拟blur

<div></div> 某个事件给div加个属性 $(div).attr(wait,true); $(div).click(function() { if(false!$(this).attr(wait)) return false; })转载于:https://www.cnblogs.com/cndxk/p/4788414.html

中国第一朵企业云

本文讲的是中国第一朵企业云&#xff0c;【IT168 资讯】算起来&#xff0c;中国中化集团公司的ERP完全运行在“云”上已经一个多月了&#xff0c;每每提到这个“创举”&#xff0c;信息技术部总经理彭劲松显得有些兴奋&#xff0c;却仍然很谨慎。作为中国第一家企业云的实践者&…

查缺补漏系统学习 EF Core 6 - 实体配置

推荐关注「码侠江湖」加星标&#xff0c;时刻不忘江湖事这是 EF Core 系列的第二篇文章&#xff0c;上一篇文章讲解了 EF Core 的一些基础概念&#xff0c;这一篇文章主要围绕实体属性的配置。点击上方或后方蓝字&#xff0c;阅读 EF Core 系列合集。实体配置配置实体的目的&am…

【ArcGIS风暴】捕捉VS经典捕捉,谁更有用武之地?

几乎所有的GIS软件都具有捕捉功能!今天我们一起来聊一聊ArcGIS软件中的捕捉功能吧。 ArcGIS软件中有两个重要的捕捉工具:捕捉和经典捕捉。 目录 一、捕捉(Snapping) 1、捕捉类型 2、捕捉选项

mysql innodb 索引 延迟更新_Mysql覆盖索引与延迟关联

延迟关联&#xff1a;通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据。为什innodb的索引叶子节点存的是主键&#xff0c;而不是像myisam一样存数据的物理地址指针&#xff1f;如果存的是物理地址指针不就不需要二次查找了吗&#xff0c;根据myisam和inn…

Android之在笔记本电脑adb devices识别不了oppo A9手机(设备管理器ADB Interface里面有个黄色感叹号)

1 问题 记本电脑adb devices识别不了oppo A9手机&#xff08;设备管理器ADB Interface里面有个黄色感叹号&#xff09; 图片如下 2 分析 很明显这里是驱动问题&#xff0c;ADB Interface有感叹号提示&#xff0c;所以这里需要解决驱动问题 3 解决办法 1&#xff09;可以尝试…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(六)精简魔法更强大

学习目标 了解对相似逻辑的简化编写——循环 推荐 1.《备受好评的看得懂的C语言入门教程》 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得懂的Python入门教程 》——&#xff08;一&#xff09;既然你选择了这系列教程那么我就要让你听得懂 第二篇&#xff1a;《假…