在创建任何对象时在 java 中保存堆栈跟踪,并在程序的任何其他点使用它

Saving stack trace in java for any object at the time of it's creation and using it at any other point in the program

出于调试目的,我想在创建对象时保存堆栈跟踪,并 refer/print 稍后在程序中保存。我尝试在 OpenJDK 本身中向对象 class 添加一个字段,但如 here 中所述,它会导致 OpenJDK 中的硬编码元素出现问题。

有人可以建议一个有效的方法来做到这一点。

如果是你的代码,你可以在构造对象的时候简单的构造一个Exception:

public class MyObject {
   public final Exception creationPoint = new Exception();

   ...
}

然后,creationPoint.printStackTrace() 将打印创建点(或者您可以调用 getStackTrace() 以编程方式查询它)。正如 GhostCat 指出的那样,收集堆栈跟踪(发生在构建 Exception 对象时)当然会影响性能,因此您通常会明智地使用此技术来调查相对不频繁生成的对象的特定问题。

为任何对象收集堆栈跟踪,并将该信息与对象一起存储,而这根本不可能以有效的方式进行。

收集堆栈跟踪信息昂贵,而且作为正常程序执行的一部分,没有办法“按比例”进行收集。请记住,堆栈跟踪的主要目的是在发生异常后收集该信息。

除此之外,它在概念上也是错误的。如果您只谈论很少的特定对象,那么适当的方法是仔细研究代码中创建这些对象的路径,并且可能让创建对象的代码进行大量日志记录。但是,如果您真的谈论许多不同种类的对象,那么您的请求反而意味着代码中的整体日志记录概念是不够的。然后专注于那部分。

JFR可能是你所需要的,该工具可以在创建对象时捕获堆栈信息,但它似乎只捕获了所有对象的一部分。

如果对象很大或很频繁,JFR 会对分配进行抽样。默认情况下,它最多采样 150 times/s.

JDK 16 或以后:

$ java -XX:StartFlightRecording:filename=exitdump.jfr MyApp
...
Stop the application
$ jfr print --events ObjectAllocationSample --stack-depth 64 exitdump.jfr

jdk.ObjectAllocationSample {
  startTime = 12:00:19.826
  objectClass = byte[] (classLoader = bootstrap)
  weight = 23.1 kB
  eventThread = "Image Animator 0" (javaThreadId = 33)
  stackTrace = [
    sun.awt.image.GifFrame.dispose() line: 723
    sun.awt.image.GifImageDecoder.produceImage() line: 247
    sun.awt.image.InputStreamImageSource.doFetch() line: 269
    sun.awt.image.ImageFetcher.fetchloop() line: 212
    sun.awt.image.ImageFetcher.run() line: 176
  ]
}
...