Log4Net LogImpl 实例过多

Too many instances of Log4Net LogImpl

我们正在使用 log4net 进行日志记录,我正在分析内存转储。我们已经将 log4net 实现包装在我们自己的 class 中,称为 "TextLogger",堆上有 6601 个实例,而 LogImpl 有 325882 个实例。

这对我来说似乎很奇怪。我们创建的记录器只存在很短的一段时间,所以我猜它们可能只是在等待被垃圾收集,但我仍然发现差异太大,无法用未清理的垃圾来解释。

从 windbg 复制,其中第一列是实例数,第二列是总大小(以字节为单位) 我们的包装器-class: 6601 211232 Logging.TextLogger

log4net classes:

325882 10428224 log4net.Repository.Hierarchy.LoggerKey

325882 20856448 log4net.Core.LogImpl

325903 20857792 log4net.Repository.LoggerRepositoryConfigurationChangedEventHandler

325882 23463504 log4net.Repository.Hierarchy.DefaultLoggerFactory+LoggerImpl

有 log4net 经验的人会说这是正常的,还是我们没有以某种方式正确处理我们的记录器实现?

我想也有可能我们以某种方式保存了对记录器的引用,以防止它们被垃圾收集,但我们没有接近相同数量的其他 classes 实例可能引用了一个记录器。

编辑: TextLogger 实现:

public class TextLogger
{
    private ILog m_Logger;
    private string m_UniqueId;

    static TextLogger()
    {
        var stream = File.OpenRead(@"log4net.config");
        log4net.Config.XmlConfigurator.Configure(stream);
    }

    public TextLogger(string name, object owner)
    {
        m_UniqueId = Guid.NewGuid().ToString("n").Substring(0, 6);
        if (false && owner != null)
        {
            m_Logger = log4net.LogManager.GetLogger(string.Format("{0}-{1}", m_UniqueId, name), owner.GetType());
        }
        else
        {
            m_Logger = log4net.LogManager.GetLogger(string.Format("{0}-{1}", m_UniqueId, name));
        }
    }

    public void Debug(string msg)
    {
        m_Logger.Debug(msg);
    }

    public void Error(string msg)
    {
        m_Logger.Error(msg);
    }

    public void Error(string msg, Exception exception)
    {
        m_Logger.Error($"{msg}, {exception.ToString().Replace(Environment.NewLine, "<br>")}");
    }
    public void Warn(string msg)
    {
        m_Logger.Warn(msg);
    }
}

我看到对于 TextLogger 的每个实例,都会实例化一个具有基于 Guid 的唯一名称的新 log4net.ILog:

m_Logger = log4net.LogManager.GetLogger(string.Format("{0}-{1}", m_UniqueId, name));

log4net.LogManager 返回的 ILog 在您的应用程序期间保持 'alive'。这使得稍后可以通过其名称再次检索相同的 ILog 实例。

因为您的所有实例都有唯一的名称,所以它们会在此处计数。

使用 log4net 时,典型的设置是根据 component/class 使用静态记录器,如下所示。尝试将您的代码重构为类似的东西。

class Foo
{
    private static ILog _logger = LogManager.Instance.GetLogger(typeof(Foo));

    public void DoSomething()
    {
        _logger.Info("Doing something"); 
    }
}

这个概念在 log4net website 中有很好的解释。