Log4Net LogImpl的实例太多

时间:2018-05-28 14:05:26

标签: c# memory-leaks log4net windbg heap-memory

我们正在使用log4net进行日志记录,而我正在分析内存转储。我们将log4net实现包装在我们自己的类“TextLogger”中,堆中有6601个实例,而LogImpl有325882个实例。

这对我来说很奇怪。我们创造的记录器只能存活一段时间,所以我猜它们可能只是等待被收集,但我仍然觉得差异太大而不能被未清理的垃圾剥夺。

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

log4net类:

325882 10428224 log4net.Repository.Hierarchy.LoggerKey

325882 20856448 log4net.Core.LogImpl

325903 20857792 log4net.Repository.LoggerRepositoryConfigurationChangedEventHandler

325882 23463504 log4net.Repository.Hierarchy.DefaultLoggerFactory + LoggerImpl

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

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

编辑: 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);
    }
}

1 个答案:

答案 0 :(得分:1)

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

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

由log4net.LogManager重新调整的ILog保持“活着”状态。在您的申请期间。这使得以后可以通过其名称再次检索相同的ILog实例成为可能。

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

使用log4net时,典型的设置是每个组件/类使用一个静态记录器,如下所示。尝试将代码重构为类似的东西。

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

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

这个概念在log4net website中得到了很好的解释。