我们正在使用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);
}
}
答案 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中得到了很好的解释。