首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我是否可以实例化一个异常并保留它供以后使用,并且如果它从未被抛出,就可以避免代价高昂的堆栈跟踪?

我是否可以实例化一个异常并保留它供以后使用,并且如果它从未被抛出,就可以避免代价高昂的堆栈跟踪?
EN

Stack Overflow用户
提问于 2016-08-05 03:54:23
回答 2查看 62关注 0票数 1

我正在考虑的情况是在一个多读应用程序中使用它。假设我的主线程(我们将其称为Prime)需要启动另一个线程(我们将其称为Daemon)来在后台执行某些操作。

守护程序线程可以从Prime线程中的几个不同位置启动,如果守护程序线程遇到错误,我想知道Prime线程中最初启动守护程序线程的哪段代码失败了。

因此,假设我在Prime线程中创建了一个new Exception("some message"),将其传递给守护线程(例如,在其构造函数中),然后启动守护线程。

如果守护进程执行时没有错误,则永远不会使用异常,并且我希望避免支付跟踪堆栈的成本。

另一方面,如果守护进程有异常发生,我希望它能够使用来自Prime线程的异常以及守护进程自己的异常来帮助调试。来自Prime线程异常的堆栈跟踪将指示守护进程产生的位置,而来自守护进程的堆栈跟踪将指示在守护进程中遇到问题的位置。

如果我这样做,我是否必须为每种情况支付Prime线程的异常的处理成本,或者只是在Daemon线程遇到错误并随后查看Prime线程的异常堆栈的情况下?

EN

回答 2

Stack Overflow用户

发布于 2016-08-05 05:46:21

异常的堆栈跟踪是在构造异常时填充的。如果您查看java.lang.Throwable的构造函数,它们看起来都像something like

代码语言:javascript
运行
复制
public Throwable() {
  fillInStackTrace();
}

public Throwable(String message) {
  fillInStackTrace();
  detailMessage = message;
}

其中fillInStackTrace()是构建堆栈跟踪的方法。所以,是的,你必须支付堆栈跟踪构造的成本,无论它是否被抛出。

然而,我预计构造线程的成本会高得多。

票数 1
EN

Stack Overflow用户

发布于 2016-08-05 06:42:57

据我所知,您希望在创建新线程的地方保留堆栈跟踪的某些部分,以便进一步调试。

当然,您可以只调用new Exception().getStackTrace(),但它可能是您的瓶颈,因为遍历所有堆栈并不便宜。如果您使用的是HotSpot,则可以使用私有StackTraceElement访问一个API,这是最常见的情况,通常足以满足调试/日志记录的需要。sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement()就是该应用程序接口,但在JDK9中将不可用。在JDK9中,您将能够使用Stack-Walking API

这是一个基准测试

代码语言:javascript
运行
复制
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class StackTraces {

    @Benchmark
    public StackTraceElement[] getStackTrace() {
        return new Exception().getStackTrace();
    }

    @Benchmark
    public StackTraceElement getFast() {
        return sun.misc.SharedSecrets.getJavaLangAccess()
                                     .getStackTraceElement(new Exception(), 2);
    }
}

结果是:

代码语言:javascript
运行
复制
Benchmark                  Mode  Cnt   Score   Error  Units
StackTraces.getFast        avgt    5   2.799 ± 0.066  us/op
StackTraces.getStackTrace  avgt    5  14.014 ± 0.290  us/op

附注:你可以通过重写fillInStackTrace来创建没有任何堆栈跟踪的异常(非常便宜)。此外,如果您在快速路径上抛出异常,HotSpot可以对其进行缓存,并省去创建堆栈跟踪。可以使用选项-XX:-OmitStackTraceInFastThrow禁用此行为

代码语言:javascript
运行
复制
new Exception() {
    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38776308

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档