记录对象的内存使用情况

kma*_*ks2 5 .net c# 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");
   ...
}
Run Code Online (Sandbox Code Playgroud)

这可以在不附加某些调试工具的情况下完成,以便可以使用部署方案吗?

wag*_*ghe 1

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

如果您需要缓存公开完整的IDictionary功能,您可以实现该接口,委托给“真实”字典并修改AddRemove操作中的累积大小值。如果您不需要缓存来公开完整的IDictionary功能,只需定义一个精简的接口(可能只有AddContains、 和Remove方法以及一个CumulativeSize属性。或者,您可能决定实现一个没有接口的缓存对象。如果是我的话,我会使用IDictionary或定义一个接口,例如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; }
}
Run Code Online (Sandbox Code Playgroud)

这非常粗糙。显然,它可以更高效、更稳健。我没有进行任何检查AddRemove查看密钥是否已经存在等,但我想您可能已经明白了。此外,作为值存储在字典中的字符串可能可以在外部进行修改(可能不在您的程序中,但理论上),因此从字符串中删除值时减去字符串的CumulativeSize长度缓存可能与最初添加该字符串时的长度不同。如果这是一个问题,您可以考虑在内部字典中存储值的副本。我对你的申请了解不够,无法判断这是否是一个好主意。

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

  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
  }
Run Code Online (Sandbox Code Playgroud)

祝你好运!