[Java] 观察加载的类的数量的变化

背景

  • java 命令的一些选项可以帮助我们观察加载的类的名称,
  • jstat 命令的 -class 选项可以显示加载的类的数量。
    结合这两点,我们就可以着手写个小程序,来观察加载的类的数量的变化过程。

思路

  1. 既然要观察数量变化的过程,那么我们希望在加载类时有明显的停顿(否则变化太快,太难观察)。
    我们可以借助 java.util.Scanner 类的 nextLine() 方法,来让程序进行等待。
  2. 既然是观察变化,那么我们希望能多观察几次,所以可以写个 for 循环来加载若干个类

代码

假设当前目录名为 load_test
我们需要创建

  1. Main.java
  2. generate.sh
    这两个文件。其中 Main.java 用于加载一些类,这些类是通过 generate.sh 文件生成的。
    两个文件的具体内容如下

Main.java

import java.util.Scanner;

public class Main {
  public static void main(String[] args) throws Exception {
    int cnt = 10;
    if (args.length > 0) {
        cnt = Integer.parseInt(args[1]);        
    }
    Scanner scanner = new Scanner(System.in);
    for (int i = 1; i <= cnt;i++) {
        scanner.nextLine();
        Class.forName("temp.C" + i);
    }
    // 为了便于观察,不让程序自动结束
    while (true);
  }
}

generate.sh

#!/bin/bash

# 如果名为 "temp" 的目录不存在, 则创建它
# 如果名为 "temp" 的目录已经存在, 则删除这个目录下的文件
dir_name="temp"
if [ ! -d "${dir_name}" ];
then
  mkdir ${dir_name}
else
  rm ${dir_name}/*
fi

# cnt 的默认值是 10, 可以被命令行参数替代
cnt="10"
if [ "$#" -gt 0 ];
then
  cnt=${1}
fi

for i in $(seq 1 ${cnt})
do
  echo "package ${dir_name};" > "${dir_name}/C${i}.java"
  echo "public class C${i} {}" >> "${dir_name}/C${i}.java"
done

javac ${dir_name}/*.java

测试

比如我们想观察5个类的加载情况,那么可以这样操作

  1. 在命令行窗口(简称为窗口 A )中执行 ./generate.sh 5 命令
    生成5个 java 文件
  2. 在窗口 A 中执行 javac Main.java 命令
    编译 Main.java
  3. 在窗口 A 中执行 java -verbose:class -XX:+TraceClassLoading -cp . Main 5 命令
    运行 Main 类
  4. 另开一个命令行窗口(简称为窗口 B ),执行 jps -l 命令,并在输出中找到和 Main 对应的那一行(下图中用红框标出来了)
    找到对应的进程id
  1. 在窗口 B 中执行jstat -class 21844 500命令(注意21844需要替换为和 Main 对应的进程id, 500表示每隔 500ms 输出一次)

    观察加载的类的数量

    我运行时,看到的效果是 571,说明此时已经加载了 571 个类

  2. 在窗口 A 中随便输入一行内容(最省事的办法就是直接敲回车键),然后就会看到有新的类被加载了(红框里是新加载的类,其中 temp.C1 这个类是由 generate.sh 生成的)

    有两个类刚刚被加载

  1. 在窗口 B 中观察,会看到加载的类的数量确实增加了2

    在窗口B进行确认

  2. 在窗口 A 中继续输入内容,然后在窗口 B 中观察

    继续加载其他类

generate.sh 一共创建了 5 个类,在上图可以看到,这 5 个类都被加载了。在窗口 B 中可以看到加载的类的数量最终变成了 577

在窗口B进行确认

  1. 由于 Main.java 中的代码不会自动结束,所以需要在窗口 A 中用 Ctrl+C 来终止对应的进程。

补充说明

  1. 关于 jstat 命令的 -class 选项的介绍可以参考 https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#class_option
  2. 在窗口 A 执行命令时,只使用 -verbose:class 选项或者 -XX:+TraceClassLoading 选项似乎就能看到同样的效果。关于这两个选项的介绍可以参考 https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html 一文

你可能感兴趣的:([Java] 观察加载的类的数量的变化)