不幸的是,我忘记记录进行堆转储的时间。我希望标准库在堆中的某个地方缓存类似
System.currentTimeMillis()
的内容。不幸的是,我没有任何缓存它的业务对象。
一个困难的选择是浏览所有线程,并查看它们的局部变量是否在某处存储了时间戳。然而,这不是我可以应用于所有堆转储的技术。
我查看了 openJDK 中的 java.lang.System,看起来我们没有缓存值。我们使用本机代码来获取当前时间,但我们不会将本机代码的结果存储在任何地方。 https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/4d891c8db5c1/src/share/classes/java/lang/System.java
堆转储文件的标头中包含时间戳。但开头有一个以零结尾的字符串,如果字符串不总是相同,这将使时间戳的确切位置动态变化。
因此,对于实际文件中的简短临时查找,您可以简单地假设通常的位置并将时间戳提取为
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));
}