Hotspot 的 Serviceability Agent 是个很强大的JVM 监控工具集合(这里简称SA),我们可以通过SA 提供的Java API(sa-jdi.jar)做很多有趣的事情。今天我们就通过SA的API导出 JVM实例中加载的Class文件。
1、编写测试类DumpClassTest
public class DumpClassTest{
public static void main(String[] args){
while(true){
try{
Thread.sleep(1000);
}catche(Exception e){}
}
}
}
2、编写DumpClass类,该类依赖
/home/tools/jdk1.6.0_43/lib/sa-jdi.jar
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import sun.jvm.hotspot.bugspot.BugSpotAgent;
import sun.jvm.hotspot.memory.SystemDictionary;
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.jcore.ClassWriter;
public class DumpVMClass {
private static JarOutputStream jarStream;
//导出目录地址
private static String outputDirectory = "/home/tools/jdk1.6.0_43/class/";
public static void main(String[] args){
BugSpotAgent agent = new BugSpotAgent();
try {
int pid = Integer.parseInt(args[0]);
agent.attach(pid);
boolean isJavaMode = agent.isJavaMode();
if(isJavaMode){
SystemDictionary dict = VM.getVM().getSystemDictionary();
dict.classesDo(new SystemDictionary.ClassVisitor() {
public void visit(Klass k) {
if (!(k instanceof InstanceKlass)) return;
try {
DumpVMClass.dumpKlass((InstanceKlass)k);
} catch (Exception e) {
System.out.println(k.getName().asString());
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}finally{
agent.detach();
}
}
private static void dumpKlass(InstanceKlass kls) {
String klassName = kls.getName().asString();
klassName = klassName.replace('/', File.separatorChar);
try {
OutputStream os = null;
if (DumpVMClass.jarStream != null) {
DumpVMClass.jarStream.putNextEntry(new JarEntry(klassName + ".class"));
os = DumpVMClass.jarStream;
} else {
int index = klassName.lastIndexOf(File.separatorChar);
File dir = null;
if (index != -1) {
String dirName = klassName.substring(0, index);
dir = new File(DumpVMClass.outputDirectory, dirName);
} else {
dir = new File(DumpVMClass.outputDirectory);
}
dir.mkdirs();
File f = new File(dir, klassName.substring(index + 1) + ".class");
f.createNewFile();
os = new BufferedOutputStream(new FileOutputStream(f));
}
try {
ClassWriter cw = new ClassWriter(kls, os);
cw.write();
} finally {
if (os != DumpVMClass.jarStream)
os.close();
}
}
catch (IOException exp) {
exp.printStackTrace();
}
}
}
3、先运行DumpClassTest:
[root@oem-ci3bcm02f1h bin]# javac DumpClassTest.java
[root@oem-ci3bcm02f1h bin]# java DumpClassTest &
[5] 14060
[root@oem-ci3bcm02f1h bin]#
4、获得PID 14060 后运行 DumpVMClass:
[root@oem-ci3bcm02f1h bin]# javac -cp .:../lib/sa-jdi.jar DumpVMClass.java
[root@oem-ci3bcm02f1h bin]# java -cp .:../lib/sa-jdi.jar DumpVMClass 14060
[root@oem-ci3bcm02f1h bin]#
5、运行完就可以看到:
/home/tools/jdk1.6.0_43/class/ 目录下该JVM 14060进程 的class文件都被dump出来了。
注:
以上DumpVMClass 代码大部分来自于sa-jdi.jar 的
sun.jvm.hotspot.tools.jcore.ClassDump