精华内容
下载资源
问答
  • 如何dump出一个Java进程里的类对应的Class文件? 大家可能对JVM很好奇,想看看运行中某时刻上JVM里各种内部数据结构的状态。可能有人想看堆上所有对象都有哪些,分别位于哪个分代之类;可能有人想看当前所有线程...
    如何dump出一个Java进程里的类对应的Class文件?

    大家可能对JVM很好奇,想看看运行中某时刻上JVM里各种内部数据结构的状态。可能有人想看堆上所有对象都有哪些,分别位于哪个分代之类;可能有人想看当前所有线程的stack trace;可能有人想看一个方法是否被JIT编译过,被编译后的native代码是怎样的。对Sun HotSpot JVM而言,这些需求都有现成的API可以满足——通过[url=http://openjdk.java.net/groups/hotspot/docs/Serviceability.html]Serviceability Agent[/url](下面简称SA)。大家熟悉的jstack、jmap等工具在使用-F参数启动时其实就是通过SA来实现功能的。

    这里介绍的是按需把class给dump出来的方法。
    为什么我们要dump运行中的JVM里的class呢?直接从classpath上把Class文件找到不就好了么?这样的话只要用ClassLoader.getResourceAsStream(name)就能行了。例如说要找foo.bar.Baz的Class文件,类似这样就行:
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    InputStream in = loader.getResourceAsStream("foo/bar/Baz.class");
    // 从in把内容拿出来,然后随便怎么处理

    用Groovy的交互式解释器shell来演示一下:
    D:\>\sdk\groovy-1.7.2\bin\groovysh
    Groovy Shell (1.7.2, JVM: 1.6.0_20)
    Type 'help' or '\h' for help.
    -----------------------------------------------------------------------------
    groovy:000> loader = Thread.currentThread().contextClassLoader
    ===> org.codehaus.groovy.tools.RootLoader@61de33
    groovy:000> stream = loader.getResourceAsStream('java/util/ArrayList.class')
    ===> sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5dfaf1
    groovy:000> file = new File('ArrayList.class')
    ===> ArrayList.class
    groovy:000> file.createNewFile()
    ===> true
    groovy:000> file << stream
    ===> ArrayList.class
    groovy:000> quit

    这样就在当前目录建了个ArrayList.class文件,把java.util.ArrayList对应的Class文件拿到手了。

    问题是,上述方式其实只是借助ClassLoader把它在classpath上能找到的Class文件复制了一份而已。如果我们想dump的类在加载时被修改过(例如说某些AOP的实现会这么做),或者在运行过程中被修改过(通过HotSwap),或者干脆就是运行时才创建出来的,那就没有现成的Class文件了。

    需要注意,java.lang.Class<T>这个类虽然实现了java.io.Serializable接口,但直接将一个Class对象序列化是得不到对应的Class文件的。参考[url=http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/2d585507a41b/src/share/classes/java/lang/Class.java]src/share/classes/java/lang/Class.java[/url]里的注释:
    package java.lang;

    import java.io.ObjectStreamField;
    // ...

    public final
    class Class<T> implements java.io.Serializable,
    java.lang.reflect.GenericDeclaration,
    java.lang.reflect.Type,
    java.lang.reflect.AnnotatedElement {
    /**
    * Class Class is special cased within the Serialization Stream Protocol.
    *
    * A Class instance is written initially into an ObjectOutputStream in the
    * following format:
    * <pre>
    * <code>TC_CLASS</code> ClassDescriptor
    * A ClassDescriptor is a special cased serialization of
    * a <code>java.io.ObjectStreamClass</code> instance.
    * </pre>
    * A new handle is generated for the initial time the class descriptor
    * is written into the stream. Future references to the class descriptor
    * are written as references to the initial class descriptor instance.
    *
    * @see java.io.ObjectStreamClass
    */
    private static final ObjectStreamField[] serialPersistentFields =
    new ObjectStreamField[0];

    // ...
    }


    =================================================================

    HotSpot有一套私有API提供了对JVM内部数据结构的审视功能,称为Serviceability Agent。它是一套Java API,虽然HotSpot是用C++写的,但SA提供了HotSpot中重要数据结构的Java镜像类,所以可以直接写Java代码来查看一个跑在HotSpot上的Java进程的内部状态。它也提供了一些封装好的工具,可以直接在命令行上跑,包括下面提到的ClassDump工具。
    SA的一个重要特征是它是“进程外审视工具”。也就是说,SA并不运行在要审视的目标进程中,而是运行在一个独立的Java进程中,通过操作系统上提供的调试API来连接到目标进程上。这样,SA的运行不会受到目标进程状态的影响,因而可以用于审视一个已经挂起的Java进程,或者是core dump文件。当然,这也就意味这一个SA进程不能用于审视自己。
    一个被调试器连接上的进程会被暂停下来。所以在SA连接到目标进程时,目标进程也是一直处于暂停状态的,直到SA解除连接。如果需要在线上使用SA的话需要小心,不要通过SA做过于耗时的分析,宁可先把数据都抓出来,把SA的连接解除掉之后再离线分析。目前的使用经验是,连接上一个小Java进程的话很快就好了,但连接上一个“大”的Java进程(堆比较大、加载的类比较多)可能会在连接阶段卡住好几分钟,线上需要慎用。

    目前(JDK6)在Windows上SA没有随HotSpot一起发布,所以无法在Windows上使用;在Linux、Solaris、Mac上使用都没问题。从JDK7 build 64开始Windows版JDK也带上SA,如果有兴趣尝鲜JDK7的话可以试试([url]http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html[/url]),当前版本是build 103;正式的JDK7今年10月份应该有指望吧。
    在Windows版JDK里带上SA的相关bug是:
    [url=http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6743339]Bug 6743339: Enable building sa-jdi.jar and sawindbg.dll on Windows with hotspot build[/url]
    [url=http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6755621]Bug 6755621: Include SA binaries into Windows JDK[/url]

    前面废话了那么多,接下来回到正题,介绍一下ClassDump工具。
    SA自带了一个能把当前在HotSpot中加载了的类dump成Class文件的工具,称为ClassDump。它的全限定类名是sun.jvm.hotspot.tools.jcore.ClassDump,有main()方法,可以直接从命令行执行;接收一个命令行参数,是目标Java进程的进程ID,可以通过JDK自带的jps工具查找Java进程的ID。要执行该工具需要确保SA的JAR包在classpath上,位于$JAVA_HOME/lib/sa-jdi.jar。
    默认条件下执行ClassDump会把当前加载的所有Java类都dump到当前目录下,如果有全限定名相同但内容不同的类同时存在于一个Java进程中,那么dump的时候会有覆盖现象,实际dump出来的是同名的类的最后一个(根据ClassDump工具的遍历顺序)。
    如果需要指定被dump的类的范围,可以自己写一个过滤器,在启动ClassDump工具时指定-Dsun.jvm.hotspot.tools.jcore.filter=filterClassName,具体方法见下面例子;如果需要指定dump出来的Class文件的存放路径,可以用-Dsun.jvm.hotspot.tools.jcore.outputDir=path来指定,path替换为实际路径。

    以下演示在Linux上进行。大家或许已经知道,Sun JDK对反射调用方法有一些特别的优化,会[url=http://rednaxelafx.iteye.com/blog/548536]在运行时生成专门的“调用类”来提高反射调用的性能[/url]。这次演示就来看看生成的类是什么样子的。

    首先编写一个自定义的过滤器。只要实现sun.jvm.hotspot.tools.jcore.ClassFilter接口即可。
    import sun.jvm.hotspot.tools.jcore.ClassFilter;
    import sun.jvm.hotspot.oops.InstanceKlass;

    public class MyFilter implements ClassFilter {
    @Override
    public boolean canInclude(InstanceKlass kls) {
    String klassName = kls.getName().asString();
    return klassName.startsWith("sun/reflect/GeneratedMethodAccessor");
    }
    }

    InstanceKlass对应于HotSpot中表示Java类的内部对象。Sun JDK为反射调用生成的类的名字形如sun/reflect/GeneratedMethodAccessorN,其中N是一个整数;所以只要看看类名是否以"sun/reflect/GeneratedMethodAccessor"开头就能找出来了。留意到这里包名的分隔符是“/”而不是“.”,这是Java类在JVM中的“内部名称”形式,参考[url=http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#14757]Java虚拟机规范第二版4.2小节[/url]。

    接下来写一个会引发JDK生成反射调用类的演示程序:
    import java.lang.reflect.Method;

    public class Demo {
    public static void main(String[] args) throws Exception {
    Method p = System.out.getClass().getMethod("println", String.class);
    for (int i = 0; i < 16; i++) {
    p.invoke(System.out, "demo");
    }
    System.in.read(); // block the program
    }
    }


    让Demo跑起来,然后先不要让它结束。通过jps工具看看它的进程ID是多少:
    [sajia@sajia class_dump]$ jps
    20542 Demo
    20554 Jps


    接下来执行ClassDump,指定上面自定义的过滤器(过滤器的类要在classpath上,本例中它在./bin):
    [sajia@sajia class_dump]$ java -classpath ".:./bin:$JAVA_HOME/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=MyFilter sun.jvm.hotspot.tools.jcore.ClassDump 20542

    执行结束后,可以看到dump出了一个Class文件,在./sun/reflect/GeneratedMethodAccessor1.class;.是默认的输出目录,后面的目录结构对应包名。

    用javap看看这个Class文件有啥内容:
    [sajia@sajia class_dump]$ javap -verbose sun.reflect.GeneratedMethodAccessor1
    public class sun.reflect.GeneratedMethodAccessor1 extends sun.reflect.MethodAccessorImpl
    minor version: 0
    major version: 46
    Constant pool:
    const #1 = Asciz sun/reflect/GeneratedMethodAccessor1;
    const #2 = class #1; // sun/reflect/GeneratedMethodAccessor1
    const #3 = Asciz sun/reflect/MethodAccessorImpl;
    const #4 = class #3; // sun/reflect/MethodAccessorImpl
    const #5 = Asciz java/io/PrintStream;
    const #6 = class #5; // java/io/PrintStream
    const #7 = Asciz println;
    const #8 = Asciz (Ljava/lang/String;)V;
    const #9 = NameAndType #7:#8;// println:(Ljava/lang/String;)V
    const #10 = Method #6.#9; // java/io/PrintStream.println:(Ljava/lang/String;)V
    const #11 = Asciz invoke;
    const #12 = Asciz (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;;
    const #13 = Asciz java/lang/String;
    const #14 = class #13; // java/lang/String
    const #15 = Asciz java/lang/Throwable;
    const #16 = class #15; // java/lang/Throwable
    const #17 = Asciz java/lang/ClassCastException;
    const #18 = class #17; // java/lang/ClassCastException
    const #19 = Asciz java/lang/NullPointerException;
    const #20 = class #19; // java/lang/NullPointerException
    const #21 = Asciz java/lang/IllegalArgumentException;
    const #22 = class #21; // java/lang/IllegalArgumentException
    const #23 = Asciz java/lang/reflect/InvocationTargetException;
    const #24 = class #23; // java/lang/reflect/InvocationTargetException
    const #25 = Asciz <init>;
    const #26 = Asciz ()V;
    const #27 = NameAndType #25:#26;// "<init>":()V
    const #28 = Method #20.#27; // java/lang/NullPointerException."<init>":()V
    const #29 = Method #22.#27; // java/lang/IllegalArgumentException."<init>":()V
    const #30 = Asciz (Ljava/lang/String;)V;
    const #31 = NameAndType #25:#30;// "<init>":(Ljava/lang/String;)V
    const #32 = Method #22.#31; // java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
    const #33 = Asciz (Ljava/lang/Throwable;)V;
    const #34 = NameAndType #25:#33;// "<init>":(Ljava/lang/Throwable;)V
    const #35 = Method #24.#34; // java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V
    const #36 = Method #4.#27; // sun/reflect/MethodAccessorImpl."<init>":()V
    const #37 = Asciz java/lang/Object;
    const #38 = class #37; // java/lang/Object
    const #39 = Asciz toString;
    const #40 = Asciz ()Ljava/lang/String;;
    const #41 = NameAndType #39:#40;// toString:()Ljava/lang/String;
    const #42 = Method #38.#41; // java/lang/Object.toString:()Ljava/lang/String;
    const #43 = Asciz Code;
    const #44 = Asciz Exceptions;
    const #45 = Asciz java/lang/Boolean;
    const #46 = class #45; // java/lang/Boolean
    const #47 = Asciz (Z)V;
    const #48 = NameAndType #25:#47;// "<init>":(Z)V
    const #49 = Method #46.#48; // java/lang/Boolean."<init>":(Z)V
    const #50 = Asciz booleanValue;
    const #51 = Asciz ()Z;
    const #52 = NameAndType #50:#51;// booleanValue:()Z
    const #53 = Method #46.#52; // java/lang/Boolean.booleanValue:()Z
    const #54 = Asciz java/lang/Byte;
    const #55 = class #54; // java/lang/Byte
    const #56 = Asciz (B)V;
    const #57 = NameAndType #25:#56;// "<init>":(B)V
    const #58 = Method #55.#57; // java/lang/Byte."<init>":(B)V
    const #59 = Asciz byteValue;
    const #60 = Asciz ()B;
    const #61 = NameAndType #59:#60;// byteValue:()B
    const #62 = Method #55.#61; // java/lang/Byte.byteValue:()B
    const #63 = Asciz java/lang/Character;
    const #64 = class #63; // java/lang/Character
    const #65 = Asciz (C)V;
    const #66 = NameAndType #25:#65;// "<init>":(C)V
    const #67 = Method #64.#66; // java/lang/Character."<init>":(C)V
    const #68 = Asciz charValue;
    const #69 = Asciz ()C;
    const #70 = NameAndType #68:#69;// charValue:()C
    const #71 = Method #64.#70; // java/lang/Character.charValue:()C
    const #72 = Asciz java/lang/Double;
    const #73 = class #72; // java/lang/Double
    const #74 = Asciz (D)V;
    const #75 = NameAndType #25:#74;// "<init>":(D)V
    const #76 = Method #73.#75; // java/lang/Double."<init>":(D)V
    const #77 = Asciz doubleValue;
    const #78 = Asciz ()D;
    const #79 = NameAndType #77:#78;// doubleValue:()D
    const #80 = Method #73.#79; // java/lang/Double.doubleValue:()D
    const #81 = Asciz java/lang/Float;
    const #82 = class #81; // java/lang/Float
    const #83 = Asciz (F)V;
    const #84 = NameAndType #25:#83;// "<init>":(F)V
    const #85 = Method #82.#84; // java/lang/Float."<init>":(F)V
    const #86 = Asciz floatValue;
    const #87 = Asciz ()F;
    const #88 = NameAndType #86:#87;// floatValue:()F
    const #89 = Method #82.#88; // java/lang/Float.floatValue:()F
    const #90 = Asciz java/lang/Integer;
    const #91 = class #90; // java/lang/Integer
    const #92 = Asciz (I)V;
    const #93 = NameAndType #25:#92;// "<init>":(I)V
    const #94 = Method #91.#93; // java/lang/Integer."<init>":(I)V
    const #95 = Asciz intValue;
    const #96 = Asciz ()I;
    const #97 = NameAndType #95:#96;// intValue:()I
    const #98 = Method #91.#97; // java/lang/Integer.intValue:()I
    const #99 = Asciz java/lang/Long;
    const #100 = class #99; // java/lang/Long
    const #101 = Asciz (J)V;
    const #102 = NameAndType #25:#101;// "<init>":(J)V
    const #103 = Method #100.#102; // java/lang/Long."<init>":(J)V
    const #104 = Asciz longValue;
    const #105 = Asciz ()J;
    const #106 = NameAndType #104:#105;// longValue:()J
    const #107 = Method #100.#106; // java/lang/Long.longValue:()J
    const #108 = Asciz java/lang/Short;
    const #109 = class #108; // java/lang/Short
    const #110 = Asciz (S)V;
    const #111 = NameAndType #25:#110;// "<init>":(S)V
    const #112 = Method #109.#111; // java/lang/Short."<init>":(S)V
    const #113 = Asciz shortValue;
    const #114 = Asciz ()S;
    const #115 = NameAndType #113:#114;// shortValue:()S
    const #116 = Method #109.#115; // java/lang/Short.shortValue:()S

    {
    public sun.reflect.GeneratedMethodAccessor1();
    Code:
    Stack=1, Locals=1, Args_size=1
    0: aload_0
    1: invokespecial #36; //Method sun/reflect/MethodAccessorImpl."<init>":()V
    4: return

    public java.lang.Object invoke(java.lang.Object, java.lang.Object[]) throws java.lang.reflect.InvocationTargetException;
    Exceptions:
    throws java.lang.reflect.InvocationTargetException Code:
    Stack=5, Locals=3, Args_size=3
    0: aload_1
    1: ifnonnull 12
    4: new #20; //class java/lang/NullPointerException
    7: dup
    8: invokespecial #28; //Method java/lang/NullPointerException."<init>":()V
    11: athrow
    12: aload_1
    13: checkcast #6; //class java/io/PrintStream
    16: aload_2
    17: arraylength
    18: sipush 1
    21: if_icmpeq 32
    24: new #22; //class java/lang/IllegalArgumentException
    27: dup
    28: invokespecial #29; //Method java/lang/IllegalArgumentException."<init>":()V
    31: athrow
    32: aload_2
    33: sipush 0
    36: aaload
    37: checkcast #14; //class java/lang/String
    40: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    43: aconst_null
    44: areturn
    45: invokespecial #42; //Method java/lang/Object.toString:()Ljava/lang/String;
    48: new #22; //class java/lang/IllegalArgumentException
    51: dup_x1
    52: swap
    53: invokespecial #32; //Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
    56: athrow
    57: new #24; //class java/lang/reflect/InvocationTargetException
    60: dup_x1
    61: swap
    62: invokespecial #35; //Method java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V
    65: athrow
    Exception table:
    from to target type
    12 40 45 Class java/lang/ClassCastException

    12 40 45 Class java/lang/NullPointerException

    40 43 57 Class java/lang/Throwable


    }


    用Java来表现这个类的话,就是:
    package sun.reflect;

    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    public GeneratedMethodAccessor1() {
    super();
    }

    public Object invoke(Object obj, Object[] args)
    throws IllegalArgumentException, InvocationTargetException {
    // prepare the target and parameters
    if (obj == null) throw new NullPointerException();
    try {
    PrintStream target = (PrintStream) obj;
    if (args.length != 1) throw new IllegalArgumentException();
    String arg0 = (String) args[0];
    } catch (ClassCastException e) {
    throw new IllegalArgumentException(e.toString());
    } catch (NullPointerException e) {
    throw new IllegalArgumentException(e.toString());
    }
    // make the invocation
    try {
    target.println(arg0);
    return null;
    } catch (Throwable t) {
    throw new InvocationTargetException(t);
    }
    }
    }

    这段Java代码跟实际的Class文件最主要的不同的地方在于实际的Class文件是用同一个异常处理器来处理ClassCastException与NullPointerException的。如果用[url=http://blogs.sun.com/darcy/entry/project_coin_multi_catch_rethrow]Java 7的多重catch语法[/url]来写的话就是:
    package sun.reflect;

    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    public GeneratedMethodAccessor1() {
    super();
    }

    public Object invoke(Object obj, Object[] args)
    throws IllegalArgumentException, InvocationTargetException {
    // prepare the target and parameters
    if (obj == null) throw new NullPointerException();
    try {
    PrintStream target = (PrintStream) obj;
    if (args.length != 1) throw new IllegalArgumentException();
    String arg0 = (String) args[0];
    } catch (final ClassCastException | NullPointerException e) {
    throw new IllegalArgumentException(e.toString());
    }
    // make the invocation
    try {
    target.println(arg0);
    return null;
    } catch (Throwable t) {
    throw new InvocationTargetException(t);
    }
    }
    }


    本来想顺带演示一下用Java反编译器把例子里的Class文件反编译为Java源码的,但用了[url=http://java.decompiler.free.fr/]JD[/url]和[url=http://www.varaneckas.com/jad]Jad[/url]都无法正确识别这里比较特别的Exceptions属性表,只好人肉反编译写出来……识别不出来也正常,毕竟Java 7之前在Java源码这层是没办法对同一个异常处理器处理指定多个异常类型。

    要深究的话,上面人肉反编译的Java文件跟实际Class文件还有些细节差异。
    例如说JDK在生成Class文件时为了方便所以把一大堆“很可能会用到”的常量都写到常量池里了,但在代码里可能并没有用到常量池里的所有项;如果用javac编译Java源码就不会出现这种状况。
    又例如生成的Class文件里一个局部变量也没用,locals=3之中三个都是参数:第一个是this,第二个是obj,第三个是args。求值的中间结果全部都直接在操作数栈上用掉了。而在Java源码里无法写出这样的代码,像是说try块不能从一个表达式的中间开始之类的。

    这次就写到这里吧~
    A. Sundararajan有篇不错的文章也是讲如何从Java进程dump出Class文件的,使用的是JVMTI系的API:
    [url=http://blogs.sun.com/sundararajan/entry/retrieving_class_files_from_a]Retrieving .class files from a running app[/url]
    然后也有一篇使用SA从core dump文件中dump出Class文件的文章:
    [url=http://blogs.sun.com/sundararajan/entry/retrieving_class_files_from_a1]Retrieving .class files from a Java core dump[/url]
    展开全文
  • 如何dump出一个Java进程里的类对应的Class文件? 大家可能对JVM很好奇,想看看运行中某时刻上JVM里各种内部数据结构的状态。可能有人想看堆上所有对象都有哪些,分别位于哪个分代之类;可能有人想看当前所有线程...

    原文出处:http://rednaxelafx.iteye.com/blog/727938/


    如何dump出一个Java进程里的类对应的Class文件?

    大家可能对JVM很好奇,想看看运行中某时刻上JVM里各种内部数据结构的状态。可能有人想看堆上所有对象都有哪些,分别位于哪个分代之类;可能有人想看当前所有线程的stack trace;可能有人想看一个方法是否被JIT编译过,被编译后的native代码是怎样的。对Sun HotSpot JVM而言,这些需求都有现成的API可以满足——通过Serviceability Agent(下面简称SA)。大家熟悉的jstack、jmap等工具在使用-F参数启动时其实就是通过SA来实现功能的。

    这里介绍的是按需把class给dump出来的方法。
    为什么我们要dump运行中的JVM里的class呢?直接从classpath上把Class文件找到不就好了么?这样的话只要用ClassLoader.getResourceAsStream(name)就能行了。例如说要找foo.bar.Baz的Class文件,类似这样就行:

    Java代码  收藏代码
    1. ClassLoader loader = Thread.currentThread().getContextClassLoader();  
    2. InputStream in = loader.getResourceAsStream("foo/bar/Baz.class");  
    3. // 从in把内容拿出来,然后随便怎么处理  

    用Groovy的交互式解释器shell来演示一下:
    Groovysh代码  收藏代码
    1. D:\>\sdk\groovy-1.7.2\bin\groovysh  
    2. Groovy Shell (1.7.2, JVM: 1.6.0_20)  
    3. Type 'help' or '\h' for help.  
    4. -----------------------------------------------------------------------------  
    5. groovy:000> loader = Thread.currentThread().contextClassLoader  
    6. ===> org.codehaus.groovy.tools.RootLoader@61de33  
    7. groovy:000> stream = loader.getResourceAsStream('java/util/ArrayList.class')  
    8. ===> sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5dfaf1  
    9. groovy:000> file = new File('ArrayList.class')  
    10. ===> ArrayList.class  
    11. groovy:000> file.createNewFile()  
    12. ===> true  
    13. groovy:000> file << stream  
    14. ===> ArrayList.class  
    15. groovy:000> quit  

    这样就在当前目录建了个ArrayList.class文件,把java.util.ArrayList对应的Class文件拿到手了。

    问题是,上述方式其实只是借助ClassLoader把它在classpath上能找到的Class文件复制了一份而已。如果我们想dump的类在加载时被修改过(例如说某些AOP的实现会这么做),或者在运行过程中被修改过(通过HotSwap),或者干脆就是运行时才创建出来的,那就没有现成的Class文件了。

    需要注意,java.lang.Class<T>这个类虽然实现了java.io.Serializable接口,但直接将一个Class对象序列化是得不到对应的Class文件的。参考src/share/classes/java/lang/Class.java里的注释:
    Java代码  收藏代码
    1. package java.lang;  
    2.   
    3. import java.io.ObjectStreamField;  
    4. // ...  
    5.   
    6. public final  
    7.     class Class<T> implements java.io.Serializable,   
    8.                   java.lang.reflect.GenericDeclaration,   
    9.                   java.lang.reflect.Type,  
    10.                               java.lang.reflect.AnnotatedElement {  
    11.     /** 
    12.      * Class Class is special cased within the Serialization Stream Protocol.  
    13.      * 
    14.      * A Class instance is written initially into an ObjectOutputStream in the  
    15.      * following format: 
    16.      * <pre> 
    17.      *      <code>TC_CLASS</code> ClassDescriptor 
    18.      *      A ClassDescriptor is a special cased serialization of  
    19.      *      a <code>java.io.ObjectStreamClass</code> instance.  
    20.      * </pre> 
    21.      * A new handle is generated for the initial time the class descriptor 
    22.      * is written into the stream. Future references to the class descriptor 
    23.      * are written as references to the initial class descriptor instance. 
    24.      * 
    25.      * @see java.io.ObjectStreamClass 
    26.      */  
    27.     private static final ObjectStreamField[] serialPersistentFields =   
    28.         new ObjectStreamField[0];  
    29.       
    30.     // ...  
    31. }  


    =================================================================

    HotSpot有一套私有API提供了对JVM内部数据结构的审视功能,称为Serviceability Agent。它是一套Java API,虽然HotSpot是用C++写的,但SA提供了HotSpot中重要数据结构的Java镜像类,所以可以直接写Java代码来查看一个跑在HotSpot上的Java进程的内部状态。它也提供了一些封装好的工具,可以直接在命令行上跑,包括下面提到的ClassDump工具。
    SA的一个重要特征是它是“进程外审视工具”。也就是说,SA并不运行在要审视的目标进程中,而是运行在一个独立的Java进程中,通过操作系统上提供的调试API来连接到目标进程上。这样,SA的运行不会受到目标进程状态的影响,因而可以用于审视一个已经挂起的Java进程,或者是core dump文件。当然,这也就意味这一个SA进程不能用于审视自己。
    一个被调试器连接上的进程会被暂停下来。所以在SA连接到目标进程时,目标进程也是一直处于暂停状态的,直到SA解除连接。如果需要在线上使用SA的话需要小心,不要通过SA做过于耗时的分析,宁可先把数据都抓出来,把SA的连接解除掉之后再离线分析。目前的使用经验是,连接上一个小Java进程的话很快就好了,但连接上一个“大”的Java进程(堆比较大、加载的类比较多)可能会在连接阶段卡住好几分钟,线上需要慎用。

    目前(JDK6)在Windows上SA没有随HotSpot一起发布,所以无法在Windows上使用;在Linux、Solaris、Mac上使用都没问题。从JDK7 build 64开始Windows版JDK也带上SA,如果有兴趣尝鲜JDK7的话可以试试(http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html),当前版本是build 103;正式的JDK7今年10月份应该有指望吧。
    在Windows版JDK里带上SA的相关bug是:
    Bug 6743339: Enable building sa-jdi.jar and sawindbg.dll on Windows with hotspot build
    Bug 6755621: Include SA binaries into Windows JDK

    前面废话了那么多,接下来回到正题,介绍一下ClassDump工具。
    SA自带了一个能把当前在HotSpot中加载了的类dump成Class文件的工具,称为ClassDump。它的全限定类名是sun.jvm.hotspot.tools.jcore.ClassDump,有main()方法,可以直接从命令行执行;接收一个命令行参数,是目标Java进程的进程ID,可以通过JDK自带的jps工具查找Java进程的ID。要执行该工具需要确保SA的JAR包在classpath上,位于$JAVA_HOME/lib/sa-jdi.jar。
    默认条件下执行ClassDump会把当前加载的所有Java类都dump到当前目录下,如果有全限定名相同但内容不同的类同时存在于一个Java进程中,那么dump的时候会有覆盖现象,实际dump出来的是同名的类的最后一个(根据ClassDump工具的遍历顺序)。
    如果需要指定被dump的类的范围,可以自己写一个过滤器,在启动ClassDump工具时指定-Dsun.jvm.hotspot.tools.jcore.filter=filterClassName,具体方法见下面例子;如果需要指定dump出来的Class文件的存放路径,可以用-Dsun.jvm.hotspot.tools.jcore.outputDir=path来指定,path替换为实际路径。

    以下演示在Linux上进行。大家或许已经知道,Sun JDK对反射调用方法有一些特别的优化,会在运行时生成专门的“调用类”来提高反射调用的性能。这次演示就来看看生成的类是什么样子的。

    首先编写一个自定义的过滤器。只要实现sun.jvm.hotspot.tools.jcore.ClassFilter接口即可。
    Java代码  收藏代码
    1. import sun.jvm.hotspot.tools.jcore.ClassFilter;  
    2. import sun.jvm.hotspot.oops.InstanceKlass;  
    3.   
    4. public class MyFilter implements ClassFilter {  
    5.     @Override  
    6.     public boolean canInclude(InstanceKlass kls) {  
    7.         String klassName = kls.getName().asString();  
    8.         return klassName.startsWith("sun/reflect/GeneratedMethodAccessor");  
    9.     }  
    10. }  

    InstanceKlass对应于HotSpot中表示Java类的内部对象。Sun JDK为反射调用生成的类的名字形如sun/reflect/GeneratedMethodAccessorN,其中N是一个整数;所以只要看看类名是否以"sun/reflect/GeneratedMethodAccessor"开头就能找出来了。留意到这里包名的分隔符是“/”而不是“.”,这是Java类在JVM中的“内部名称”形式,参考Java虚拟机规范第二版4.2小节

    接下来写一个会引发JDK生成反射调用类的演示程序:
    Java代码  收藏代码
    1. import java.lang.reflect.Method;  
    2.   
    3. public class Demo {  
    4.     public static void main(String[] args) throws Exception {  
    5.         Method p = System.out.getClass().getMethod("println", String.class);  
    6.         for (int i = 0; i < 16; i++) {  
    7.             p.invoke(System.out, "demo");  
    8.         }  
    9.         System.in.read(); // block the program  
    10.     }  
    11. }  


    让Demo跑起来,然后先不要让它结束。通过jps工具看看它的进程ID是多少:
    Command prompt代码  收藏代码
    1. [sajia@sajia class_dump]$ jps  
    2. 20542 Demo  
    3. 20554 Jps  


    接下来执行ClassDump,指定上面自定义的过滤器(过滤器的类要在classpath上,本例中它在./bin):
    Command prompt代码  收藏代码
    1. [sajia@sajia class_dump]$ java -classpath ".:./bin:$JAVA_HOME/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=MyFilter sun.jvm.hotspot.tools.jcore.ClassDump 20542  

    执行结束后,可以看到dump出了一个Class文件,在./sun/reflect/GeneratedMethodAccessor1.class;.是默认的输出目录,后面的目录结构对应包名。

    用javap看看这个Class文件有啥内容:
    Javap代码  收藏代码
    1. [sajia@sajia class_dump]$ javap -verbose sun.reflect.GeneratedMethodAccessor1  
    2. public class sun.reflect.GeneratedMethodAccessor1 extends sun.reflect.MethodAccessorImpl  
    3.   minor version: 0  
    4.   major version: 46  
    5.   Constant pool:  
    6. const #1 = Asciz        sun/reflect/GeneratedMethodAccessor1;  
    7. const #2 = class        #1;     //  sun/reflect/GeneratedMethodAccessor1  
    8. const #3 = Asciz        sun/reflect/MethodAccessorImpl;  
    9. const #4 = class        #3;     //  sun/reflect/MethodAccessorImpl  
    10. const #5 = Asciz        java/io/PrintStream;  
    11. const #6 = class        #5;     //  java/io/PrintStream  
    12. const #7 = Asciz        println;  
    13. const #8 = Asciz        (Ljava/lang/String;)V;  
    14. const #9 = NameAndType  #7:#8;//  println:(Ljava/lang/String;)V  
    15. const #10 = Method      #6.#9;  //  java/io/PrintStream.println:(Ljava/lang/String;)V  
    16. const #11 = Asciz       invoke;  
    17. const #12 = Asciz       (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;;  
    18. const #13 = Asciz       java/lang/String;  
    19. const #14 = class       #13;    //  java/lang/String  
    20. const #15 = Asciz       java/lang/Throwable;  
    21. const #16 = class       #15;    //  java/lang/Throwable  
    22. const #17 = Asciz       java/lang/ClassCastException;  
    23. const #18 = class       #17;    //  java/lang/ClassCastException  
    24. const #19 = Asciz       java/lang/NullPointerException;  
    25. const #20 = class       #19;    //  java/lang/NullPointerException  
    26. const #21 = Asciz       java/lang/IllegalArgumentException;  
    27. const #22 = class       #21;    //  java/lang/IllegalArgumentException  
    28. const #23 = Asciz       java/lang/reflect/InvocationTargetException;  
    29. const #24 = class       #23;    //  java/lang/reflect/InvocationTargetException  
    30. const #25 = Asciz       <init>;  
    31. const #26 = Asciz       ()V;  
    32. const #27 = NameAndType #25:#26;//  "<init>":()V  
    33. const #28 = Method      #20.#27;        //  java/lang/NullPointerException."<init>":()V  
    34. const #29 = Method      #22.#27;        //  java/lang/IllegalArgumentException."<init>":()V  
    35. const #30 = Asciz       (Ljava/lang/String;)V;  
    36. const #31 = NameAndType #25:#30;//  "<init>":(Ljava/lang/String;)V  
    37. const #32 = Method      #22.#31;        //  java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V  
    38. const #33 = Asciz       (Ljava/lang/Throwable;)V;  
    39. const #34 = NameAndType #25:#33;//  "<init>":(Ljava/lang/Throwable;)V  
    40. const #35 = Method      #24.#34;        //  java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V  
    41. const #36 = Method      #4.#27; //  sun/reflect/MethodAccessorImpl."<init>":()V  
    42. const #37 = Asciz       java/lang/Object;  
    43. const #38 = class       #37;    //  java/lang/Object  
    44. const #39 = Asciz       toString;  
    45. const #40 = Asciz       ()Ljava/lang/String;;  
    46. const #41 = NameAndType #39:#40;//  toString:()Ljava/lang/String;  
    47. const #42 = Method      #38.#41;        //  java/lang/Object.toString:()Ljava/lang/String;  
    48. const #43 = Asciz       Code;  
    49. const #44 = Asciz       Exceptions;  
    50. const #45 = Asciz       java/lang/Boolean;  
    51. const #46 = class       #45;    //  java/lang/Boolean  
    52. const #47 = Asciz       (Z)V;  
    53. const #48 = NameAndType #25:#47;//  "<init>":(Z)V  
    54. const #49 = Method      #46.#48;        //  java/lang/Boolean."<init>":(Z)V  
    55. const #50 = Asciz       booleanValue;  
    56. const #51 = Asciz       ()Z;  
    57. const #52 = NameAndType #50:#51;//  booleanValue:()Z  
    58. const #53 = Method      #46.#52;        //  java/lang/Boolean.booleanValue:()Z  
    59. const #54 = Asciz       java/lang/Byte;  
    60. const #55 = class       #54;    //  java/lang/Byte  
    61. const #56 = Asciz       (B)V;  
    62. const #57 = NameAndType #25:#56;//  "<init>":(B)V  
    63. const #58 = Method      #55.#57;        //  java/lang/Byte."<init>":(B)V  
    64. const #59 = Asciz       byteValue;  
    65. const #60 = Asciz       ()B;  
    66. const #61 = NameAndType #59:#60;//  byteValue:()B  
    67. const #62 = Method      #55.#61;        //  java/lang/Byte.byteValue:()B  
    68. const #63 = Asciz       java/lang/Character;  
    69. const #64 = class       #63;    //  java/lang/Character  
    70. const #65 = Asciz       (C)V;  
    71. const #66 = NameAndType #25:#65;//  "<init>":(C)V  
    72. const #67 = Method      #64.#66;        //  java/lang/Character."<init>":(C)V  
    73. const #68 = Asciz       charValue;  
    74. const #69 = Asciz       ()C;  
    75. const #70 = NameAndType #68:#69;//  charValue:()C  
    76. const #71 = Method      #64.#70;        //  java/lang/Character.charValue:()C  
    77. const #72 = Asciz       java/lang/Double;  
    78. const #73 = class       #72;    //  java/lang/Double  
    79. const #74 = Asciz       (D)V;  
    80. const #75 = NameAndType #25:#74;//  "<init>":(D)V  
    81. const #76 = Method      #73.#75;        //  java/lang/Double."<init>":(D)V  
    82. const #77 = Asciz       doubleValue;  
    83. const #78 = Asciz       ()D;  
    84. const #79 = NameAndType #77:#78;//  doubleValue:()D  
    85. const #80 = Method      #73.#79;        //  java/lang/Double.doubleValue:()D  
    86. const #81 = Asciz       java/lang/Float;  
    87. const #82 = class       #81;    //  java/lang/Float  
    88. const #83 = Asciz       (F)V;  
    89. const #84 = NameAndType #25:#83;//  "<init>":(F)V  
    90. const #85 = Method      #82.#84;        //  java/lang/Float."<init>":(F)V  
    91. const #86 = Asciz       floatValue;  
    92. const #87 = Asciz       ()F;  
    93. const #88 = NameAndType #86:#87;//  floatValue:()F  
    94. const #89 = Method      #82.#88;        //  java/lang/Float.floatValue:()F  
    95. const #90 = Asciz       java/lang/Integer;  
    96. const #91 = class       #90;    //  java/lang/Integer  
    97. const #92 = Asciz       (I)V;  
    98. const #93 = NameAndType #25:#92;//  "<init>":(I)V  
    99. const #94 = Method      #91.#93;        //  java/lang/Integer."<init>":(I)V  
    100. const #95 = Asciz       intValue;  
    101. const #96 = Asciz       ()I;  
    102. const #97 = NameAndType #95:#96;//  intValue:()I  
    103. const #98 = Method      #91.#97;        //  java/lang/Integer.intValue:()I  
    104. const #99 = Asciz       java/lang/Long;  
    105. const #100 = class      #99;    //  java/lang/Long  
    106. const #101 = Asciz      (J)V;  
    107. const #102 = NameAndType        #25:#101;//  "<init>":(J)V  
    108. const #103 = Method     #100.#102;      //  java/lang/Long."<init>":(J)V  
    109. const #104 = Asciz      longValue;  
    110. const #105 = Asciz      ()J;  
    111. const #106 = NameAndType        #104:#105;//  longValue:()J  
    112. const #107 = Method     #100.#106;      //  java/lang/Long.longValue:()J  
    113. const #108 = Asciz      java/lang/Short;  
    114. const #109 = class      #108;   //  java/lang/Short  
    115. const #110 = Asciz      (S)V;  
    116. const #111 = NameAndType        #25:#110;//  "<init>":(S)V  
    117. const #112 = Method     #109.#111;      //  java/lang/Short."<init>":(S)V  
    118. const #113 = Asciz      shortValue;  
    119. const #114 = Asciz      ()S;  
    120. const #115 = NameAndType        #113:#114;//  shortValue:()S  
    121. const #116 = Method     #109.#115;      //  java/lang/Short.shortValue:()S  
    122.   
    123. {  
    124. public sun.reflect.GeneratedMethodAccessor1();  
    125.   Code:  
    126.    Stack=1, Locals=1, Args_size=1  
    127.    0:   aload_0  
    128.    1:   invokespecial   #36; //Method sun/reflect/MethodAccessorImpl."<init>":()V  
    129.    4:   return  
    130.   
    131. public java.lang.Object invoke(java.lang.Object, java.lang.Object[])   throws java.lang.reflect.InvocationTargetException;  
    132.   Exceptions:   
    133.    throws java.lang.reflect.InvocationTargetException  Code:  
    134.    Stack=5, Locals=3, Args_size=3  
    135.    0:   aload_1  
    136.    1:   ifnonnull       12  
    137.    4:   new     #20; //class java/lang/NullPointerException  
    138.    7:   dup  
    139.    8:   invokespecial   #28; //Method java/lang/NullPointerException."<init>":()V  
    140.    11:  athrow  
    141.    12:  aload_1  
    142.    13:  checkcast       #6; //class java/io/PrintStream  
    143.    16:  aload_2  
    144.    17:  arraylength  
    145.    18:  sipush  1  
    146.    21:  if_icmpeq       32  
    147.    24:  new     #22; //class java/lang/IllegalArgumentException  
    148.    27:  dup  
    149.    28:  invokespecial   #29; //Method java/lang/IllegalArgumentException."<init>":()V  
    150.    31:  athrow  
    151.    32:  aload_2  
    152.    33:  sipush  0  
    153.    36:  aaload  
    154.    37:  checkcast       #14; //class java/lang/String  
    155.    40:  invokevirtual   #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
    156.    43:  aconst_null  
    157.    44:  areturn  
    158.    45:  invokespecial   #42; //Method java/lang/Object.toString:()Ljava/lang/String;  
    159.    48:  new     #22; //class java/lang/IllegalArgumentException  
    160.    51:  dup_x1  
    161.    52:  swap  
    162.    53:  invokespecial   #32; //Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V  
    163.    56:  athrow  
    164.    57:  new     #24; //class java/lang/reflect/InvocationTargetException  
    165.    60:  dup_x1  
    166.    61:  swap  
    167.    62:  invokespecial   #35; //Method java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V  
    168.    65:  athrow  
    169.   Exception table:  
    170.    from   to  target type  
    171.     12    40    45   Class java/lang/ClassCastException  
    172.   
    173.     12    40    45   Class java/lang/NullPointerException  
    174.   
    175.     40    43    57   Class java/lang/Throwable  
    176.   
    177.   
    178. }  


    用Java来表现这个类的话,就是:
    Java代码  收藏代码
    1. package sun.reflect;  
    2.   
    3. public class GeneratedMethodAccessor1 extends MethodAccessorImpl {  
    4.     public GeneratedMethodAccessor1() {  
    5.         super();  
    6.     }  
    7.       
    8.     public Object invoke(Object obj, Object[] args)  
    9.             throws IllegalArgumentException, InvocationTargetException {  
    10.         // prepare the target and parameters  
    11.         if (obj == nullthrow new NullPointerException();  
    12.         try {  
    13.             PrintStream target = (PrintStream) obj;  
    14.             if (args.length != 1throw new IllegalArgumentException();  
    15.             String arg0 = (String) args[0];  
    16.         } catch (ClassCastException e) {  
    17.             throw new IllegalArgumentException(e.toString());  
    18.         } catch (NullPointerException e) {  
    19.             throw new IllegalArgumentException(e.toString());  
    20.         }  
    21.         // make the invocation  
    22.         try {  
    23.             target.println(arg0);  
    24.             return null;  
    25.         } catch (Throwable t) {  
    26.             throw new InvocationTargetException(t);  
    27.         }  
    28.     }  
    29. }  

    这段Java代码跟实际的Class文件最主要的不同的地方在于实际的Class文件是用同一个异常处理器来处理ClassCastException与NullPointerException的。如果用Java 7的多重catch语法来写的话就是:
    Java代码  收藏代码
    1. package sun.reflect;  
    2.   
    3. public class GeneratedMethodAccessor1 extends MethodAccessorImpl {  
    4.     public GeneratedMethodAccessor1() {  
    5.         super();  
    6.     }  
    7.       
    8.     public Object invoke(Object obj, Object[] args)  
    9.             throws IllegalArgumentException, InvocationTargetException {  
    10.         // prepare the target and parameters  
    11.         if (obj == nullthrow new NullPointerException();  
    12.         try {  
    13.             PrintStream target = (PrintStream) obj;  
    14.             if (args.length != 1throw new IllegalArgumentException();  
    15.             String arg0 = (String) args[0];  
    16.         } catch (final ClassCastException | NullPointerException e) {  
    17.             throw new IllegalArgumentException(e.toString());  
    18.         }  
    19.         // make the invocation  
    20.         try {  
    21.             target.println(arg0);  
    22.             return null;  
    23.         } catch (Throwable t) {  
    24.             throw new InvocationTargetException(t);  
    25.         }  
    26.     }  
    27. }  


    本来想顺带演示一下用Java反编译器把例子里的Class文件反编译为Java源码的,但用了JDJad都无法正确识别这里比较特别的Exceptions属性表,只好人肉反编译写出来……识别不出来也正常,毕竟Java 7之前在Java源码这层是没办法对同一个异常处理器处理指定多个异常类型。

    要深究的话,上面人肉反编译的Java文件跟实际Class文件还有些细节差异。
    例如说JDK在生成Class文件时为了方便所以把一大堆“很可能会用到”的常量都写到常量池里了,但在代码里可能并没有用到常量池里的所有项;如果用javac编译Java源码就不会出现这种状况。
    又例如生成的Class文件里一个局部变量也没用,locals=3之中三个都是参数:第一个是this,第二个是obj,第三个是args。求值的中间结果全部都直接在操作数栈上用掉了。而在Java源码里无法写出这样的代码,像是说try块不能从一个表达式的中间开始之类的。

    展开全文
  • JVM进程的工作目录

    2015-11-19 22:55:17
    每次我们用Java命令运行我们的Java程序,都会在JVM中开启一个进程,对于每一个进程,都会有一个相对应的工作目录,这个工作目录在虚拟机初始化的时候就已经设置好了,默认的情况下,工作目录是我们工程的根目录,  ...
    每次我们用Java命令运行我们的Java程序,都会在JVM中开启一个进程,对于每一个进程,都会有一个相对应的工作目录,这个工作目录在虚拟机初始化的时候就已经设置好了,默认的情况下,工作目录是我们工程的根目录, 
    
     
    比如: 
    /home/test/Project- --bin --divinemind.onlyfun.test.helloworld.java --src



     假如我们在用下面的命令启动helloworld,那么这个进程的根目录就是/home/test/Project/bin,helloworld里进行操作需要的资源,比如文件什么的,都会在这个目录进行查找。在Windows下,情况也是相同的。 

    我们可以通过 

    --------------------- 
    System.getProperty(“user.dir”); 
    ---------------------- 

    取得当前进程的工作目录,而且当我们想改变这个工作目录的时候,也可以通过 

    --------------------- 
    System.setProperty(“user.dir”,”/home/test/xxxxxxx”); 
    --------------------- 

    设置当前进程的工作目录,但是,事实上,user.dir这个系统环境是不可以重新设置的,问题很多,最常见的问题,当前进程下的所有线程都在使用这个环境变量,如果修改的话,危险可想而知,Sun的JDK这样做估计是一个小BUG. 
    参见下面的连接: 

    http://gcc.gnu.org/ml/java/2000-q1/msg00408.html 
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4045688 

      所以,System.setProperty这个方法只是让我们看看,实际上没有作用。在Sun的JDK1.4中,当前进程的工作目录是没有办法修改的,在JDK1.5中,ProcessBuilder在这方面有所改进。 

      当我们没有选择需要使用非工作目录下的资源的时候,比如:Java调用A, A使用B,B和A在同一个目录下,A和B不在当前进程的工作目录下,这样的话,程序肯定运行会有问题,这个时候有两个办法可以解决 

      1. 所有的路径都写绝对路径 

      所有的路径写绝对路径可以实现,但是程序在部署的时候麻烦非常多,维护也困难,但是方法简单,直观。 

      2. 在当前进程中新开一个子进程,修改子进程的工作目录 

      在Java中新开一个子进程的方法跟JDK版本有关: 

    A.JDK1.4中: 

    ------------------------- 
    Process process = System.getRuntime.exec(arg1,arg2,arg3); 
    arg1:系统命令 
    arg2:命令运行的环境变量 
    arg3:子进程的工作目录,在这个地方就可以设置我们自己想要的工作目录,达到使用非父进程工作目下资源的方法。 
    ------------------------- 

    B. JDK1.5中: 

      在这个版本中,我们可以使用ProcessBuilder来新开一个JVM进程。 

      下面的代码可以实现这里我们的功能:

    ------------------------ ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2"); // myDir就是当前进程的工作目录,如果不设置,那就是默认为父进程的工作//目录 pb.directory("myDir"); Process p = pb.start(); ---------------------------------



      Java在平时跟操作系统的关系确实很少,我们都很少碰到问题,但是如果我们调用操作系统命令什么的时候,麻烦就多起来了,不过如果我们更多地了解JVM,问题就是比较容易解决了。

    展开全文
  • 在java中,Runtime类表示运行时操作类,是一个封装了JVM进程的类,每一个JVM对应着一个Runtime类的实例,此实例由JVM运行时为其实例化。 下面图示演示了其方法以及应用。

    在java中,Runtime类表示运行时操作类,是一个封装了JVM进程的类,每一个JVM都对应着一个Runtime类的实例,此实例由JVM运行时为其实例化。

    下面图示演示了其方法以及应用。






    展开全文
  • JVM

    2017-03-08 20:39:34
    JVM的生命周期 一、首先分析两个概念 JVM实例和JVM执行引擎实例 ...(1)JVM实例对应了一个独立运行的Java程序 ... 它是进程级别 ...(2)JVM执行引擎实例则对应了属于用户运行... 当启动一个Java程序时,一个JVM
  • Jvm

    2016-03-28 22:28:00
    先加载继承的夫类,再加载子类 先加载初始化方法,再加载变量 Java-编译成class-jvm加载类(分配内存)-解码-成机器码-本机执行 ...启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static voi...
  • JVM总结()

    2016-08-21 11:32:13
    Jvm实战 Jvm运行时 程序计数器: Jvm进程内每个线程私有,记录当前线程中字节码执行的行号....方法调用直至完成对应一个栈帧在虚拟机栈中的出入栈. 局部变量表所需的内存空间是在编译期间完成分配的.局部变量表中存
  • jvm-堆

    2020-07-16 11:22:43
    一个java程序对应一个进程,一个进程对应一个jvm实例,一个jvm实例对应一个堆空间和方法区 一个进程中的多个线程共享同一个java堆,但还可以划分线程私有的缓冲区(TLAB) 复制代码 堆空间参数设置 参数 详细 ...
  • JVM-堆

    2021-02-01 19:45:51
    一个进程对应一个JVM实例,一个JVM实例对应一个运行时数据区,而其中的所有线程都共享同一个堆和方法区,因此堆必须考虑线程安全的问题。 JVM启动实际:BootStrap 一、堆空间 每一个java程序对应一个进程,也就是一...
  • JVM调优经历

    2019-04-19 12:50:10
    free -g 内存过多 1、top M---查看内存排序 P----查看CPU排序 ...操作系统里每打开一个程序都会创建一个进程ID,即PID。 2、top -H -p 74142 二、查看对应进程的java堆栈信息 查看进程中的线程 ps -m...
  • 《深入理解JVM》读书系列一 一、 JVM的生命周期 ...启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点 b)
  • 每次我们用Java命令运行我们的Java程序,都会在JVM中开启一个进程,对于每一个进程,都会有一个相对应的工作目录,这个工作目录在虚拟机初始化的时候就已经设置好了,默认的情况下,工作目录是我们工程的根目录,...
  • JVM基础

    2020-08-06 16:20:14
    本文首先介绍一下Java虚拟机的生存周期,然后大致介绍JVM的体系结构,最后对体系结构中...JVM实例的诞生: 当启动一个java程序时,一个JVM实例就诞生了,任何一个拥有public static void main(String[] args)函数的cla
  • JVM是Java应用程序的运行环境,每个Java应用程序,通过main方法作为执行入口启动后,在操作系统中都会对应一个JVM进程。 Java应用程序在启动时,需要加载实际执行的类的类文件.class,从而获取类的字段,方法,常量...
  • JVM存储区域

    2019-06-25 15:41:34
    每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,每一个线程有一个自己私有的栈。进程所创建的所有类的实例(也就...
  • JVM4-堆

    2020-10-07 17:41:53
    一个进程对应一个JVM实例, 一个JVM对应一个运行时数据区(Runtime Data Area), 一个运行时数据区里有方法区和堆, 一个进程里有多个线程,共享方法区和堆空间, 每一个线程都有一个程序计数器、本地方法栈、...
  • JVM总结

    2019-01-20 11:46:35
    JVM执行流程 .java文件被编译为.class文件 ...启动,启动一个java程序时,一个JVM实例就产生了,任何一个用户public static void main的函数的class都可以作为JVM实例的运行起点 运行,main()作为该程序初始线程...
  • jvm运行内存分配

    2016-10-27 18:43:00
    引用 ... 一、基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆...
  • JVM详解

    2012-05-02 18:04:23
    首先这里澄清两个概念: JVM实例和JVM执行引擎实例,JVM实例对应了一个独立运行的Java程序,而JVM...JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有publicstaticvoidmain(String[]ar...
  • JVM调优

    2019-12-09 16:24:38
    JVM调优 一.CPU过高 1.查看jvm的进程ID,...linux下,所有的java内部线程,其实都对应一个进程id,也就是说,linux上的sun jvm将java程序中的线程映射为了操作系统进程 3.将线程ID转化为16进制 printf “%x\n” ...
  • java JVM

    2012-03-20 09:52:11
    首先这里澄清两个概念:JVM实例和JVM执行引擎实例, JVM实例对应了一个独立运行的Java程序, 而JVM执行引擎实例则对应了...JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有publicstaticv...
  • jvm堆空间

    2020-10-30 23:04:03
    堆空间对进程来说是唯一的,线程是共享的,一个进程对应一个JVM实例。 一个JVM实例只存在一个堆内存,堆也是java内存管理的核心区域。 Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块...
  • jvm-堆理解

    2021-06-16 01:36:31
    方法区和堆是线程共享的,是每个进程唯一的,一个java程序对应一个进程,一个进程对应jvm实例,一个jvm实例拥有一个单例的运行时数据区,堆是java内存管理的核心区域 堆的大小可以被调节,通过-Xms和-Xmx参数调节 ...
  • android 几个进程概念

    2016-01-26 13:51:21
    init 和linux一样,都是在硬件初始化后操作系统第一个进程 servicemanager 负责管理服务的,添加服务,获取服务的作用 zygote 受精卵进程,也就是app_...开启进程system-server,启动jvm这样一般一个应用对应一个

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 691
精华内容 276
关键字:

一个进程对应一个jvm