c# - 记录对象的内存使用情况

标签 c# .net memory

可能有 5 或 6 个 SO 帖子与此无关,但没有一个真正回答这个问题。

我有一个 Dictionary 对象,用作存储值的缓存。问题是我不知道它有多大——随着时间的推移它可能会变大或不会变大,但我无法判断,所以我无法衡量它的有效性,也无法对用户如何使用该软件做出结论.因为这是一个将投入生产并在很长一段时间内监控某些东西的作品,所以附加内存分析器或任何类似的调试工具没有意义。

理想情况下,我会简单地在我的 Timer 中调用它来执行如下操作:

private void someTimer_Tick(object sender, EventArgs e)
{
   ...
   float mbMem = cacheMap.GetMemorySize();
   RecordInLog(DateTime.Now.ToString() + ": mbMem is using " + mbMem.ToString() + "MB of memory");
   ...
}

这是否可以在不附加一些调试工具的情况下完成,以便它可以在部署的场景中使用?

最佳答案

鉴于您最近的评论,该值是一个可变长度的字符串,计算字典中每个项目的大小应该很容易。我会考虑通过创建自己的缓存对象(可能只是包装一个字典)并在将项目添加到缓存和从缓存中删除时跟踪总大小来节省时间和精力。这样,在任何时间点,您都可以通过查看一直跟踪的值来判断缓存中值的总大小。

如果您需要您的缓存来公开完整的 IDictionary功能,您可以实现接口(interface),委托(delegate)给“真实”字典并修改 Add 中的累积大小值。和 Remove操作。如果您不需要缓存来公开完整的 IDictionary功能,只需定义一个精简的接口(interface)(可能只有 AddContainsRemove 方法和一个 CumulativeSize 属性。或者,您可能决定实现一个没有接口(interface)的缓存对象。如果是我,我会使用 IDictionary 或定义一个接口(interface),例如 ICache

因此,您的缓存可能看起来像这样(未编译和未测试):

public interface ICacheWithCumulativeSize
{
  void Add(string key, string value);
  bool Contains(string key);
  void Remove(string key);
  int CumulativeSize { get; }
}

public class MyCache : ICacheWithCumulativeSize
{
  private IDictionary<string, string> dict = new Dictionary<string, string>();

  public void Add(string key, string value)
  {
    CumulativeSize += value.Length;
    dict[key] = value;
  }

  public bool Contains(string key)
  {
    return dict.ContainsKey(key);
  }

  public void Remove(string key)
  {
    string toRemove = dict[key];
    CumulativeSize -= value.Length;
    dict.Remove(key);
  }

  int CumulativeSize { public get; private set; }
}

这很粗糙。显然,它可以更高效、更健壮。我没有做任何检查 AddRemove查看 key 是否已存在等,但我认为您可能明白了。此外,作为值存储在字典中的字符串可能会在外部被修改(可能不在您的程序中,但理论上如此),因此从 CumulativeSize 中减去字符串的长度。从缓存中删除值的时间可能与最初添加该字符串时的长度不同。如果这是一个问题,您可以考虑将值的副本存储在内部字典中。我对您的应用程序了解不多,无法判断这是否是个好主意。

为了完整性...这是一个粗略的实现,它简单地包装了一个字典,公开了 IDictionary 接口(interface),并跟踪缓存中项目的总大小。它有更多的防御代码,主要是为了保护大小累加器。我可能认为棘手的唯一部分是索引 setter ......我的实现检查要设置的索引是否已经存在。如果是这样,则根据输入值的大小适本地递减累积值,然后递增。否则,我认为这非常简单。

  public class MySpecialDictionary : IDictionary<string, string>
  {
    private IDictionary<string, string> dict = new Dictionary<string, string>();

    public int TotalSize { get; private set; }

    #region IDictionary<string,string> Members

    public void Add(string key, string value)
    {
      dict.Add(key, value);
      TotalSize += string.IsNullOrEmpty(value) ? 0 : value.Length;
    }

    public bool ContainsKey(string key)
    {
      return dict.ContainsKey(key);
    }

    public ICollection<string> Keys
    {
      get { return dict.Keys; }
    }

    public bool Remove(string key)
    {
      string value;
      if (dict.TryGetValue(key, out value))
      {
        TotalSize -= string.IsNullOrEmpty(value) ? 0 : value.Length;
      }
      return dict.Remove(key);
    }

    public bool TryGetValue(string key, out string value)
    {
      return dict.TryGetValue(key, out value);
    }

    public ICollection<string> Values
    {
      get { return dict.Values; }
    }

    public string this[string key]
    {
      get
      {
        return dict[key];
      }
      set
      {
        string v;
        if (dict.TryGetValue(key, out v))
        {
          TotalSize -= string.IsNullOrEmpty(v) ? 0 : v.Length;
        }
        dict[key] = value;
        TotalSize += string.IsNullOrEmpty(value) ? 0 : value.Length;
      }
    }

    #endregion

    #region ICollection<KeyValuePair<string,string>> Members

    public void Add(KeyValuePair<string, string> item)
    {
      dict.Add(item);
      TotalSize += string.IsNullOrEmpty(item.Value) ? 0 : item.Value.Length;
    }

    public void Clear()
    {
      dict.Clear();
      TotalSize = 0;
    }

    public bool Contains(KeyValuePair<string, string> item)
    {
      return dict.Contains(item);
    }

    public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
    {
      dict.CopyTo(array, arrayIndex);
    }

    public int Count
    {
      get { return dict.Count; }
    }

    public bool IsReadOnly
    {
      get { return dict.IsReadOnly; }
    }

    public bool Remove(KeyValuePair<string, string> item)
    {
      string v;
      if (dict.TryGetValue(item.Key, out v))
      {
        TotalSize -= string.IsNullOrEmpty(v) ? 0 : v.Length;
      }
      return dict.Remove(item);
    }

    #endregion

    #region IEnumerable<KeyValuePair<string,string>> Members

    public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
    {
      return dict.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return dict.GetEnumerator();
    }

    #endregion
  }

祝你好运!

关于c# - 记录对象的内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8387694/

相关文章:

c++ - 可以更改 std::string 容量以进行优化吗?

ruby-on-rails - 如何测量每个 gem 在初始化时需要多少内存?

c# - Umbraco RelationService.GetByParentId(memberId) 慢。每个项目触发两个查询

c# - 如何使用 C# 创建 .dbf 文件?

c# - 如何在屏幕上获取鼠标 WM_MouseMove 消息?

c# - 使用C#下载多个网页的最快方法

c# - 根级别的数据无效。第 1 行,位置 1。读取 xml 时

c# - 按特定顺序读取文件?

c# - .NET 对象的内存开销是多少

c++ - 是否可以创建一个 C 文件对象以在内存中读/写