我该如何测量JVM启动时间?

13

我有一个用Java编写的应用程序,我想知道在达到static void int main(String args)之前需要多长时间以及它在这个阶段正在做什么,我该怎么做?

我知道微软有一个名为MPGO(Manager profile guided optimisation)的工具,Java有类似的工具吗?

4个回答

13

在Java应用程序内部测量启动时间的简单方法:

import java.lang.management.ManagementFactory;

public class Test {

    public static void main(String[] args) {
        long currentTime = System.currentTimeMillis();
        long vmStartTime = ManagementFactory.getRuntimeMXBean().getStartTime();
        System.out.println(currentTime - vmStartTime);
    }
}

您可以使用 JVMTI代理跟踪虚拟机事件,例如类加载、垃圾回收、方法编译等。这里有一个我制作的简单代理 - vmtrace(以及 Windows的编译dll)。

运行java -agentpath:path\to\vmtrace.dll Main,事件跟踪将被打印到stderr中:

[0.00000] VMTrace started
[0.00182] Dynamic code generated: flush_icache_stub
[0.00187] Dynamic code generated: get_cpu_info_stub
[0.00519] Dynamic code generated: getCPUIDNameInfo_stub
[0.00524] Dynamic code generated: forward exception
[0.00526] Dynamic code generated: call_stub
...
[0.01182] Loading class: java/lang/Object
[0.01198] Loading class: java/lang/String
[0.01206] Loading class: java/io/Serializable
...
[0.05620] VM initialized
[0.05664] Class prepared: java/lang/invoke/MethodHandle
[0.05672] Loading class: java/lang/invoke/MethodHandleImpl
[0.05732] Class prepared: java/lang/invoke/MethodHandleImpl
[0.05738] Loading class: java/lang/invoke/MethodHandleImpl$1
[0.05743] Class prepared: java/lang/invoke/MethodHandleImpl$1
[0.05755] Loading class: java/lang/invoke/MethodHandleImpl$2
[0.05759] Loading class: java/util/function/Function
[0.05768] Class prepared: java/util/function/Function
...

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Har
1
@Har 是的,在多线程环境下,由于并发问题,输出可能会出现混合。应该使用一个互斥锁来包围trace函数以解决这个问题。最好将代理输出与应用程序输出分开 - 您可以将文件名指定为代理参数。 - apangin
1
@Har 我已经更新了 vmtrace,使其输出同步,并记录了 [VM destroyed]。 - apangin

4
使用 Java 9,您可以添加 -Xlog:class+init=info:file=trace.log 来跟踪类初始化(这是类加载后的下一步),然后过滤出您的主类。这是一个新的 日志记录功能
您还可以告诉它记录所有内容以查看启动前发生了什么,但记录的事件数量可能会扭曲结果。
在 Java 8 及更低版本中,不同的 VM 组件具有自己的日志记录(通常只通过 printf),而类加载则不包括时间戳。

你如何指定启用时间戳?我迄今为止找不到该选项,我已经使用了-XX:+ TraceClassResolution -XX:+ TraceClassLoading -XX:+ UnlockDiagnosticVMOptions -XX:LogFile = C:\ Users \ Har \ out.txt -XX:+ PrintCompilation。 - Har
1
抱歉,我记错了,在8中,你只能获得打印编译和垃圾回收日志的时间戳(这两者都无法确定启动时间),而不能获得类加载的时间戳。我想这些不一致性之一就是他们在9中统一日志记录的原因。 - the8472

3

另一种测量启动时间的方法是使用自Java 9以来可用的ProcessHandle

public static void main(String[] args) {
    var currentTimeMillis = System.currentTimeMillis();
    var processStartTime = ProcessHandle.current().info().startInstant().get();
    System.out.println(currentTimeMillis - processStartTime.toEpochMilli());
}

0
如果您使用jrockit jvm,可以添加以下标志来了解jvm启动的时间。
-Xverbose:codegen

更多细节在这里https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/slow_start.html#wp1083972

更新 5/9/2016

根据我们以下的对话。 jstat将提供关于类加载器的基于时间的统计信息。必须通过执行获取虚拟机id(vmid)

jps

使用此ID可以执行以下操作

jstat -class {vmid} 1000 10

这将在十秒钟内每秒提供一次类加载器的快照。


这些选项在免费的Java 8 SE版本中可用吗? - Har
1
最好的功能已经合并到热点中。请查看以下页面中“调试”标题下的信息,以获取Java 8 se的相关内容。http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html - James McGuigan
1
看看 ciTime 或者追踪类加载 - James McGuigan
我明白你所说的调试选项:http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html 那里有一个非常有用的调试部分。 - Har
你在哪个平台上? - James McGuigan
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接