如何在Java 8中获取最后几个堆栈帧而不是完整的堆栈跟踪? [英] How to get last few stack frames instead of a complete stack trace in Java 8?

查看:81
本文介绍了如何在Java 8中获取最后几个堆栈帧而不是完整的堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 9中提供了Stack Walking API,该API使我们仅能获取最后两个堆栈帧.但是我对Java 8有所了解.在Java 8中,我们可以使用Thread.currentThread().getStackTrace()new Throwable().getStackTrace()来获取堆栈跟踪,但是这两种方法都很慢,因为它们构成了整个堆栈跟踪.有什么方法可以限制堆栈跟踪中的帧数(例如仅构造最后3帧)?

There is the Stack Walking API in Java 9 which allows us to get only the last couple of stack frames. 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. Is there any way to limit the number of frames in the stack trace (to construct only the last 3 frames for example)?

更新: 我测试了Stephen的代码,它确实运行良好.实际上,根据选择的深度,它可以将执行时间减少恒定的因素.我发现有趣的是,即使堆栈跟踪是在异常创建期间构造并以内部格式存储的,它也不会减少创建新异常的时间.调用getStackTrace()时,大部分时间都花费在将内部格式转换为StackTraceElement上.因此,如果堆栈跟踪较浅,则转换它所需的时间当然会更少.但是为什么在创建异常(new Throwable())时创建堆栈跟踪的内部表示不需要花费更少的时间呢?

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. 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())?


    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);
    }

更新2:为消除Benchamrk问题,我将所有Throwable实例存储在一个数组中,然后在执行结束时我随机地检索了其中一个实例并打印了堆栈跟踪.我认为这将阻止为消除new Throwable()调用而进行的任何优化.

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. I think this would prevent any optimizations done to eliminate the new Throwable() calls.

        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]);

推荐答案

您可以使用JVM选项-XX:MaxJavaStackTraceDepth=depth来限制堆栈跟踪的大小.

You can use the JVM option -XX:MaxJavaStackTraceDepth=depth to limit the size of stacktraces.

但是,这适用于所有堆栈跟踪,听起来并不像您所需要的那样.我认为没有一种方法可以根据具体情况来限制大小.

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.

这篇关于如何在Java 8中获取最后几个堆栈帧而不是完整的堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆