You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

日志写入方法中执行new DirectoryInfo触发StackOverflowException,如何解决?

问题分析与解决方案

核心原因

触发StackOverflowException的关键是无限递归调用:当writeLogToFile抛出栈溢出异常后,catch块中调用AppExceptionHandler.writeException(sofex)记录异常,若这个异常处理方法内部又调用了writeLogToFile(或间接触发日志写入逻辑),就会形成循环——写异常日志→触发异常→再写异常日志,往复直到栈空间耗尽。

另外,newLogFile中重复调用Monitor.Enter(m_lock)属于冗余操作:writeLogToFile已持有同一锁,虽然Monitor支持线程重入,但这种写法会增加复杂度,甚至可能引发锁泄漏(原代码newLogFile未在finally中释放锁)。

具体修复步骤

1. 切断异常处理的递归链

修改StackOverflowException的捕获逻辑,改用无递归风险的基础方式记录异常,彻底避免循环调用:

catch (StackOverflowException sofex)
{
    try
    {
        // 直接写入固定的应急日志文件,不调用当前日志系统
        File.AppendAllText(@"C:\emergency_log_error.txt", $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 栈溢出异常: {sofex.Message}\r\n");
        // 控制台应用可同时输出到控制台
        Console.WriteLine($"栈溢出异常: {sofex.Message}");
    }
    catch { } // 极端情况忽略二次异常,避免问题扩大
}

2. 移除newLogFile中的冗余锁

由于writeLogToFile已持有锁,newLogFile无需再次获取同一锁,同时补充锁释放的finally块(原代码缺失导致锁泄漏):

private void newLogFile() 
{
    try 
    { 
        if (m_streamWriter != null) 
        { 
            endLogging(); 
            m_streamWriter.Flush(); 
            m_streamWriter.Close();
            m_streamWriter = null; // 显式置空避免后续错误
        }
        m_logFileNameSuffix = getLogFileNewSuffix();
        m_streamWriter = File.AppendText(getLogFileName());
        startLogging(); 
    }
}

3. 提前校验日志目录

在类初始化阶段完成目录校验与创建,避免每次写入时重复执行:

// 类构造函数或初始化方法中添加
public YourLoggerClass()
{
    if (string.IsNullOrWhiteSpace(m_logFileDirectory))
    {
        throw new ArgumentNullException(nameof(m_logFileDirectory), "日志目录路径不能为空");
    }
    // 提前创建目录,不存在则自动创建
    Directory.CreateDirectory(m_logFileDirectory);
}

关键注意事项

  • StackOverflowException属于.NET严重异常,抛出时栈空间已极度紧张,此时复杂操作大概率失败,异常处理逻辑必须极简。
  • 绝对禁止在捕获该异常后调用可能触发递归的方法,尤其是当前的日志写入逻辑。

内容的提问来源于stack exchange,提问作者Sujin Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:40:34