如何从堆转储中提取时间戳。

4

很遗憾,我忘记了记录生成堆转存文件的时间。我希望在堆中,标准库缓存了像System.currentTimeMillis()这样的东西。不幸的是,我没有任何缓存它的业务对象。

一种困难的选择是浏览所有线程,并查看它们的本地变量是否存储了某个时间戳。然而,这不是我能够应用于所有堆转储的技巧。

我查看了OpenJDK中的java.lang.System,看起来我们没有缓存值。我们去本地代码获取当前时间,但我们没有将从本地代码获取的结果存储在任何地方。https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/4d891c8db5c1/src/share/classes/java/lang/System.java


我不再拥有堆转储文件了,但我认为它是gzip格式,然后上传,接着下载,最后解压缩。我不确定创建日期是否仍然可用。 - joseph
1个回答

5
堆转储文件包含一个时间戳在其头部。但是在开头有一个零结尾的字符串,如果该字符串始终相同,则会使时间戳的确切位置动态化。
因此,对于实际文件的短期即席查找,您可以简单地假定通常位置并提取时间戳。
try(RandomAccessFile raf = new RandomAccessFile(hprofFileLocation, "r")) {
    raf.seek(23);
    System.out.println(hprofFileLocation+" created "+Instant.ofEpochMilli(raf.readLong()));
}

清晰的解决方案应该读取以零结尾的字符串,跳过随后的 int 值,并从结果位置读取时间戳,例如:

try(FileChannel fch = FileChannel.open(
                          Paths.get(hprofFileLocation), StandardOpenOption.READ)) {
    ByteBuffer bb = fch.map(
        FileChannel.MapMode.READ_ONLY, 0, Math.min(Integer.MAX_VALUE, fch.size()));
    do {} while(bb.get() != 0); // zero terminate string, usually "JAVA PROFILE 1.0.[12]"
    int pointerSize = bb.getInt();
    long timeStamp = bb.getLong();
    System.out.println(hprofFileLocation+" created "+Instant.ofEpochMilli(timeStamp));
}

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