• e.printStackTrace() 原理的分析


    e.printStackTrace();

    先查看下源码



    如图片中1所示,使用的是 PrintStreamOrWriter

      public void printStackTrace() {
            printStackTrace(System.err);
        }
    
        /**
         * Prints this throwable and its backtrace to the specified print stream.
         *
         * @param s {@code PrintStream} to use for output
         */
        public void printStackTrace(PrintStream s) {
            printStackTrace(new WrappedPrintStream(s));
        }
    
        private void printStackTrace(PrintStreamOrWriter s) {
            // Guard against malicious overrides of Throwable.equals by
            // using a Set with identity equality semantics.
            Set<Throwable> dejaVu =
                Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
            dejaVu.add(this);
    
            synchronized (s.lock()) {
                // Print our stack trace
                s.println(this);
                StackTraceElement[] trace = getOurStackTrace();
                for (StackTraceElement traceElement : trace)
                    s.println("	at " + traceElement);
    
                // Print suppressed exceptions, if any
                for (Throwable se : getSuppressed())
                    se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "	", dejaVu);
    
                // Print cause, if any
                Throwable ourCause = getCause();
                if (ourCause != null)
                    ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
            }
        }

    ,而这来源于 PrintStream,而 PrintStream 又继承 FilterOutputStream ,是文件输出流,会肯定会影响内存的变动
    ublic class PrintStream extends FilterOutputStream
        implements Appendable, Closeable
    {
    
        private final boolean autoFlush;
        private boolean trouble = false;
        private Formatter formatter;
    
        /**
         * Track both the text- and character-output streams, so that their buffers
         * can be flushed without flushing the entire stream.
         */
        private BufferedWriter textOut;
        private OutputStreamWriter charOut;
    
        /**
         * requireNonNull is explicitly declared here so as not to create an extra
         * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
         * early during system initialization.
         */
        private static <T> T requireNonNull(T obj, String message) {
            if (obj == null)
                throw new NullPointerException(message);
            return obj;
        }
    }

    而图片中二所示的lock锁,锁住这个流对象,就是占用住了内存不让进行gc回收,先输出打印,

    跟踪s.println(this)  也就是PrintStream的方法,发现是会使用bufferedwriter和outputstream

    /**
     * Prints an Object and then terminate the line.  This method calls
     * at first String.valueOf(x) to get the printed object's string value,
     * then behaves as
     * though it invokes <code>{@link #print(String)}</code> and then
     * <code>{@link #println()}</code>.
     *
     * @param x  The <code>Object</code> to be printed.
     */
    public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }

    /**
    * Prints a string. If the argument is <code>null</code> then the string
    * <code>"null"</code> is printed. Otherwise, the string's characters are
    * converted into bytes according to the platform's default character
    * encoding, and these bytes are written in exactly the manner of the
    * <code>{@link #write(int)}</code> method.
    *
    * @param s The <code>String</code> to be printed
    */
    public void print(String s) {
    if (s == null) {
    s = "null";
    }
    write(s);
    }

    private void write(String s) {
    try {
    synchronized (this) {
    ensureOpen();
    textOut.write(s);
    textOut.flushBuffer();
    charOut.flushBuffer();
    if (autoFlush && (s.indexOf(' ') >= 0))
    out.flush();
    }
    }
    catch (InterruptedIOException x) {
    Thread.currentThread().interrupt();
    }
    catch (IOException x) {
    trouble = true;
    }
    }
     

    后又获取 StackTraceElement ,也就是获取方法调用者的具体信息 的。 循环打印 

    然后又获取Throwable报错的堆栈跟踪异常数据 的数组, 循环打印。

    特意说下,在 printEnclosedStackTrace的方法中使用

    assert Thread.holdsLock(s.lock());
    这个是断言,判断当前线程是是否获得当前流的锁,判断是否成功。
    专业一点的词叫:为了确保该代码所在的线程正持有所在类的对象作为锁。

    意思执行的过程中,这个流对象只能被当前流锁占用不能被切换到其它线程。如果报错多的话,那么这些线程都会在统计这些报错信息,而不能去执行其它东西了

    来源

    java中e.printStackTrace()不要使用,请使用logger记录

    Thread.holdsLock(Object)方法、assert断言、宏

  • 相关阅读:
    MySQL 5.5版本数据库介绍与二进制安装
    nginx配置文件的基础优化
    yum源是什么
    微服务之间调用token管理
    微服务之间调用事务处理
    idea
    sentry
    infinispan配置
    微服务事务处理
    高并发处理
  • 原文地址:https://www.cnblogs.com/zhian/p/15066562.html
Copyright © 2020-2023  润新知