简体   繁体   English

如何在 Java 8 中获取最后几个堆栈帧而不是完整的堆栈跟踪?

[英]How to get last few stack frames instead of a complete stack trace in Java 8?

There is the Stack Walking API in Java 9 which allows us to get only the last couple of stack frames. Java 9 中有 Stack Walking API,它允许我们只获取最后几个堆栈帧。 But I am stuck with Java 8. In Java 8 we can get the Stack trace with either Thread.currentThread().getStackTrace() or new Throwable().getStackTrace() but both of these methods are slow because they construct the whole stack trace.但我坚持使用 Java 8。在 Java 8 中,我们可以使用Thread.currentThread().getStackTrace()new Throwable().getStackTrace()获取堆栈跟踪,但这两种方法都很慢,因为它们构建了整个堆栈痕迹。 Is there any way to limit the number of frames in the stack trace (to construct only the last 3 frames for example)?有什么方法可以限制堆栈跟踪中的帧数(例如,仅构造最后 3 帧)?

Update: I tested Stephen's code and it works really well.更新:我测试了斯蒂芬的代码,它运行得非常好。 It really reduces execution time by a constant factor depending on the the depth chosen.根据选择的深度,它确实将执行时间减少了一个常数。 What I found interesting is that it does not reduce the time to create a new Exception even though the stack trace is constructed during exception creation and stored in an internal format.我发现有趣的是,即使在异常创建期间构建堆栈跟踪并以内部格式存储,它也不会减少创建新异常的时间。 Most of the time is spent converting this internal format to a StackTraceElement when getStackTrace() is called.大部分时间都花在了调用getStackTrace()时将此内部格式转换为StackTraceElement So if the stack trace is shallower, than of course it takes less time to convert it.因此,如果堆栈跟踪更浅,则转换它所需的时间当然更少。 But why doesn't it take less time to create the internal representation of the stack trace when the exception is created( new Throwable() )?但是为什么在创建异常时创建堆栈跟踪的内部表示不需要更少的时间( new Throwable() )?


    public static void main(String[] args) throws IOException {
        f1();
    }

    private static void f1() {
       f2();
    }

    private static void f2() {
       f3();
    }

    private static void f3() {
       f4();
    }

    private static void f4() {
        f5();
    }

    private static void f5() {
        int sum = 0;
        long l = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            Throwable throwable = new Throwable();
            //comment out to test the internal representation -> StackTraceElement conversion
            //StackTraceElement[] trace = throwable.getStackTrace();
            //sum += trace.length;
        }
        long l2 = System.currentTimeMillis();
        System.out.println(l2-l);
        System.out.println(sum);
    }

Update 2: Trying to eliminate benchamrk issues, I stored all my Throwable instances in an array then at the end of execution I retrieved one of them by random and printed the stack trace.更新 2:为了消除 benchamrk 问题,我将所有Throwable实例存储在一个数组中,然后在执行结束时我随机检索其中一个并打印堆栈跟踪。 I think this would prevent any optimizations done to eliminate the new Throwable() calls.我认为这会阻止为消除new Throwable()调用而进行的任何优化。

        int sizez = 2000000;
        Throwable[] th = new Throwable[sizez];
        for (int i = 0; i < sizez; i++) {
            th[i] = new Throwable();
            //StackTraceElement[] trace = throwable.getStackTrace();
            //sum += trace.length;
        }
        long l2 = System.currentTimeMillis();
        System.out.println(l2-l);
        System.out.println(sum);

        Random rand = new Random();
        StackTraceElement[] trace = th[rand.nextInt(sizez)].getStackTrace();
        System.out.println(trace[0]);

You can use the JVM option -XX:MaxJavaStackTraceDepth=depth to limit the size of stacktraces.您可以使用 JVM 选项-XX:MaxJavaStackTraceDepth=depth来限制-XX:MaxJavaStackTraceDepth=depth的大小。

However, this applies to all stacktraces, and it doesn't sound like it is what you need.但是,这适用于所有堆栈跟踪,而且听起来并不是您所需要的。 I don't think there is a way to limit the size on a case by case basis.我认为没有办法根据具体情况限制大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM