java - 记录完整堆栈跟踪性能问题

标签 java logging apache-commons

我正在研究 Apache commons 库中 ExceptionUtils getFullStackTrace 的代码,如下所示:

public static String getFullStackTrace(Throwable throwable) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw, true);
            Throwable[] ts = getThrowables(throwable);
            for (int i = 0; i < ts.length; i++) {
                ts[i].printStackTrace(pw);
                if (isNestedThrowable(ts[i])) {
                    break;
                }
           }
            return sw.getBuffer().toString();
        }

我注意到它不会关闭 PrintWriter 并且仅进行自动刷新。

不关闭PrintWriter会导致内存泄漏吗?

我正在使用 FileWriter 登录到一个文件,其中发生了所有异常,并且我想使用上述方法来记录完整的堆栈跟踪。

但后来我用以下内容替换了它,因为我怀疑它会造成内存泄漏:

public static String stackTraceToString(Throwable e) throws Exception {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw,true);
        e.printStackTrace(pw);
        StringBuilder sb = new StringBuilder();
        sb.append(sw.toString());
        sw.flush();
        sw.close();
        pw.close();
        return sb.toString();
    }

您认为这两种方法对 CPU 和内存的性能如何,哪一种性能更好?

编辑:自定义记录器代码

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.faces.context.FacesContext;


public class AppLogger
{
    public static String MESSAGE_TYPE_ERROR = "ERROR";
    public static String MESSAGE_TYPE_INFO = "INFO";
    public static boolean DISABLE_LOG = false;

    private static final String _logFilePath = FacesContext.getCurrentInstance().getExternalContext().getInitParameter("LogFilePath");
    private static FileWriter _fw;
    private AppLogger() 
    {
    }


    public static String stackTraceToString(Throwable e) throws Exception {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw,true);
        e.printStackTrace(pw);
        StringBuilder sb = new StringBuilder();
        sb.append(sw.toString());
        sw.flush();
        sw.close();
        pw.close();
        return sb.toString();
    }



    public static void Log(Exception e)
    {
        if(DISABLE_LOG)
            return;
        try
        {             
            _fw = new FileWriter(_logFilePath + getFileName(), true);
            _fw.write(formatMessage(stackTraceToString(e), AppLogger.MESSAGE_TYPE_ERROR,null));
            _fw.close();
        }
        catch(IOException ex)
        {
            ex.printStackTrace();
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            releaseResources(); 
        }
    }

    private static void releaseResources()
    {
        if(_fw != null)
        {
            try
            {
                _fw.close();
                _fw = null;
            }
            catch(Exception e)
            {
               e.printStackTrace(); 
            }
        }
    }


    private static String getFileName()
    {
        GregorianCalendar gc = new GregorianCalendar();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        StringBuilder sb = new StringBuilder();
        sb.append("logFile.").append(sdf.format(gc.getTime())).append(".log");  
        return sb.toString();
    }

    private static String formatMessage(String message, String messageType,String className)
    {
        GregorianCalendar gc = new GregorianCalendar();
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a");
        StringBuilder sb = new StringBuilder();
        if(className != null)
          sb.append(sdf.format(gc.getTime())).append(" ").append(messageType).append(" ").append(className).append(" : ").append(message).append("\n");
        else
          sb.append(sdf.format(gc.getTime())).append(" ").append(messageType).append(" ").append(" : ").append(message).append("\n");
        return sb.toString();
    }
}

最佳答案

在这种情况下,不会。这是 PrintWriter.close 的代码 - 如您所见,它所做的只是关闭它包装的 Writer (out),并进行一些额外的同步和“错误处理” :

public void close() {
    try {
        synchronized (lock) {
            if (out == null)
                return;
            out.close();
            out = null;
        }
    }
    catch (IOException x) {
        trouble = true;
    }
}

在这种情况下,它关闭 StringWriter。以下是 StringWriter.close 的代码:

/**
 * Closing a <tt>StringWriter</tt> has no effect. The methods in this
 * class can be called after the stream has been closed without generating
 * an <tt>IOException</tt>.
 */
public void close() throws IOException {
}

正如您所看到的,它什么也没做 - 这是在文档中指定的,而不仅仅是实现细节。

关闭流对于文件(在这种情况下它会停止阻止其他进程写入文件)、网络连接(在这种情况下它会断开连接)以及其他几种类型的流和写入器等非常重要;但是,这对于 StringWriter(以及流等效项 ByteArrayOutputStream,以及输入等效项 StringReaderByteArrayInputStream 来说并不重要)。

关于java - 记录完整堆栈跟踪性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28134160/

相关文章:

java - 编译器会优化未使用的私有(private)方法吗?

python - 为什么 logger.info() 只在调用 logging.info() 后出现?

java - 过滤 log4j 2.0 消息以分离每个 webapp 的日志文件

java - Google Guava 与 Apache Commons

android - apache commons IOUtils.toByteArray 不为 android 编译

java - Maven tomcat 插件不接受路径

java - Maven 依赖项 :go-offline command issue

java - Apache Commons SCXML 状态机框架

java - Clojure Intellij Cursive插件JDK错误

linux - 如何在 Perl 中处理来自连续流程管道的更新