建设网站的公司汇总,线上营销策略方案,动画设计培训,粤康码小程序catalog 1. instrucment与Attach API
2. BTrace: VM Attach的两种方式
3. Sun JVM Attach API 1. instrucment与Attach API JDK5中增加了一个包java.lang.instrucment#xff0c;能够对JVM底层组件进行访问。在JDK 5中#xff0c;Instrument 要求在运行前利用命令行参数或者系…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: 动态Attachload指定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 APIMain.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的进程IDPID 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) {ListVirtualMachineDescriptor list VirtualMachine.list(); for (VirtualMachineDescriptor vmd : list) { System.out.println(pid: vmd.id() : vmd.displayName()); } }}
//tools.jar needs to be added to the IDEs library path and the programs classpath. The tools.jar file is found in the JDKs 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
{//继承HotSpotVirtualMachinesuper(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 isnt 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 its 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 processenqueue(hProcess, stub, cmd, pipename, args);// wait for command to complete - process will connect with the// completion statusconnectPipe(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