【问题标题】:Access stacktraces with good performance?访问性能良好的堆栈跟踪?
【发布时间】:2014-11-24 19:22:11
【问题描述】:

我们最近应用了几乎所有应用程序模块/组件(大约 50 个项目)都使用的缓存解决方案。为了更好地了解在不同系统“位置”上执行了哪些缓存操作,我们为当前执行的缓存操作添加了日志记录,包括堆栈跟踪,以准确了解触发缓存操作的原因。

我们当前的方法如下所示:我们从 new Throwable() 获取堆栈跟踪,过滤不相关的行并记录剩余的堆栈跟踪。但是,遗憾地创建一个新的异常来记录并不是一个便宜的操作。由于我们不直接使用缓存,而是通过休眠,所以在没有访问堆栈跟踪的情况下找出哪个调用者触发了操作并不容易。

因此,我的问题是:是否有比 Throwable().getStackTrace 或 Thread.currentThread().getStackTrace() 更高效的解决方案来访问当前的堆栈跟踪?

【问题讨论】:

  • “虽然遗憾地创建一个新的异常记录并不是一个便宜的操作”——实际上我想不出任何其他操作可能比这更昂贵。你不能从它的源代码中检测休眠吗?
  • 是的,我想我们可以。我们也讨论过这个问题,但我们想先用这个简单的解决方案进行尝试。

标签: java performance stack-trace


【解决方案1】:

Thread.currentThread().getStackTrace() 与@apangin 指出的基本相同,但如果它避免创建 Throwable,将来它可能会更快。

但是,您可能会发现二次抽样会给您带来所需的改进。不是记录每次访问,而是记录每第 N 次访问。如果您记录每 10 次访问,您可以将开销减少多达 90%,如果您有大量访问,它几乎同样准确。

另一种选择是使用像 YourKit 这样的分析器,它可以更有效地执行此操作。这可以显示一个方法的调用者有多少不同以及他们的堆栈跟踪(通常每 10 次记录一次)

【讨论】:

  • 谢谢,对于子采样建议!没想到。
  • 为什么你认为Thread.currentThread().getStackTrace() 更快?看看sources:它被实现为new Exception().getStackTrace()
  • @apangin +10 如果可以的话。谢谢。
【解决方案2】:

您还可以做的是实现java agent。这将正确检测您要跟踪的代码片段。

Here you will find how to start

【讨论】:

  • 如何避免需要进行堆栈跟踪?
  • 这个想法是使用工具接口,他可以使用方法入口事件来获取帧位置并遍历堆栈。
【解决方案3】:

其实获取异常堆栈跟踪并没有那么慢:

  • 只有 10% 时间用于收集回溯 - 这是在 Throwable() 构造函数中完成的;
  • 其他 90% 时间用于将回溯从内部格式转换为可读的 StackTraceElement[] 数组 - 这是在 getStackTrace() 中完成的。

这意味着,如果您不需要同步处理堆栈跟踪,您可以只调用new Exception()(这或多或少的快速操作),然后稍后或在另一个线程中异步调用e.getStackTrace()

此外,有时(如您的情况)不需要完整的堆栈跟踪。您可以跳过一些堆栈帧并只解码您感兴趣的那些。神奇的sun.misc.SharedSectets 类会有所帮助。

例如要仅获取第 2 到第 5 帧,请使用

Exception e = new Exception();
int depth = Math.min(5, SharedSecrets.getJavaLangAccess().getStackTraceDepth(e));

for (int frame = 2; frame < depth; frame++) {
    StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame);
    System.out.println(elem);
}

【讨论】:

  • 值得注意的是,sun.* 包是供内部使用的,不应由“最终”用户使用。这意味着,恕我直言,在创建新的 java 版本时,在保持 sun.* 包向后兼容方面比官方公开的包要少得多。
  • @reallynice 对。 SharedSecrets 适用于 Java 8。它不适用于 Java 9,但是,有一个适用于 Java 9 及更高版本的新标准 StackWalker API
猜你喜欢
  • 2021-11-03
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
相关资源
最近更新 更多