Java程序的运行离不开类的加载,为了更好地理解程序的执行,有时候需要知道系统加载了哪些类。一般情况下,系统加载的类存在于文件系统中,以jar的形式打包或者以class文件的形式存在,可以通过文件系统查看。关于类的生命周期,参见http://blog.csdn.net/zhengzhb/article/details/7517213。写得非常好,强烈推荐读。

使用参数-verbose:class跟踪类的加载与卸载

来看一段简单的代码:

1
2
3
4
public class LoadClass {
public static void main(String[] args) {
}
}

输出日志节选如下:

1
2
3
4
5
6
7
8
9
10
[Loaded java.lang.Object from D:\Major program\java\lib\rt.jar]
[Loaded java.io.Serializable from D:\Major program\java\lib\rt.jar]
[Loaded java.lang.Comparable from D:\Major program\java\lib\rt.jar]
部分输出省略
[Loaded java.security.BasicPermissionCollection from D:\Major program\java\lib\rt.jar]
[Loaded cc.shinerio.chapter3.LoadClass from file:/H:/proj/reviewJava/Learn-JavaVirtualMachine/bin/]
[Loaded sun.launcher.LauncherHelper$FXHelper from D:\Major program\java\lib\rt.jar]
[Loaded java.lang.Class$MethodArray from D:\Major program\java\lib\rt.jar]
[Loaded java.lang.Shutdown from D:\Major program\java\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from D:\Major program\java\lib\rt.jar]

可以看出系统首先加载了Object类,作为所有父类的基类,这里类并没有机会得到卸载(程序运行期间不满足类卸载条件)

使用-XX:+TraceClassLoading单独跟踪类加载,+XX:+TraceClassUnloading跟踪类卸载

类的动态加载

利用动态代理,AOP技术等,系统可以在运行时动态地生成某些类,这些类相对比较隐蔽,无法通过文件系统找到,利用跟踪技术此时就非常有必要。

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class TraceClass {
interface ObjectInterface{ //java动态代理只能针对接口进行代理
public void doSomething();
}
class RealObject implements ObjectInterface{
public void doSomething(){
System.out.println("做了一些事情");
}
}
class DynamicProxy implements InvocationHandler{
private Object realObject;

public DynamicProxy(Object realObject) {
super();
this.realObject = realObject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("准备工作");
Object o = method.invoke(realObject, args);
System.out.println("收尾工作");
return o;
}
}
public static void main(String[] args) {
RealObject oi = (new TraceClass()).new RealObject(); //被代理对象
Class realClass = oi.getClass(); //被代理对象类
InvocationHandler ih=(new TraceClass()).new DynamicProxy(oi);//持有代理对象,创建代理方法
//创建代理对象
ObjectInterface objectInterface = (ObjectInterface) Proxy.newProxyInstance(realClass.getClassLoader(), realClass.getInterfaces(),ih);
objectInterface.doSomething();
}
}

使用-XX:PrintClassHistogram,在控制台按下Crtl+Break组合件,控制台就会显示 房钱的类信息柱状图,可以看到系统中占用空间最多的对象,以及其实例数量和空间大小

系统参数的查看

Java虚拟机支持众多的可配参数,不同的参数可能对系统的执行效果有较大的影响,所以有必要明确当前系统的实际运行参数。

-XX:+PrintVMOptions打印虚拟机接受到的命令行显示参数

-XX:+PrintCommandLineFlags打印传递给虚拟机的显示和隐式参数

1
-XX:InitialHeapSize=132452736 -XX:MaxHeapSize=2119243776 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

可以看到类似如上信息,隐式参数未必是通过命令行显示指定的,可能是虚拟机启动时自行设置的。

-XX:+PrintFlagsFinal可以查看系统的详细参数