System.Runtime.Caching内存缓存c#中每个对象占用的列表大小

时间:2014-03-05 11:39:04

标签: c# caching

我正在使用c#内存缓存(System.Runtime.Caching),它正在填满,并使用比预期更多的ram。 无论如何都要列出缓存中每个对象在缓存中占用的大小

我想编写与此类似的代码,以便我可以确定哪个特定项目导致问题?

private void ListSizeOfEachItemInCache()
{
    foreach {var item in Cache.Items}
    {
        Console.WriteLine(string.Format(item.Key, item.CacheSize));
    }
}

我的项通常是包含其中集合的类,并且具有大对象图。但是,如果我将它们序列化到磁盘,使用数据协定序列化程序,它们似乎不会填充磁盘上的空间,因为它们似乎在RAM中。这使我认为文件缓存可能更好(因为从远程数据库中检索项目 - 甚至不在本地)。

private static readonly MemoryCache Cache = MemoryCache.Default;

我已经看到其他问题要求在内存中列出对象大小,但这是不同的,因为我想要它在内存缓存中占用的确切大小(我不能假设它会完全相同,也许它有一些其他开销,因为缓存需要知道一些其他数据,例如何时添加,它的到期策略等)..

1 个答案:

答案 0 :(得分:0)

是的,你不会得到一个确切的数字。您可以做的最好的事情是使用反射来迭代对象的层次结构,并使用sizeof计算所有值类型的大小。但这仍然不会告诉你一个确切的大小。

对于我提到的那个例子,你可以使用像这样的代码

void Main()
{
    var types = new List<object>{
        (byte)1,
        (short)1,
        (int)1,
        (long)1,
        (double)1,
        (decimal)1,
        (float)1,
        "omg afd obj amd",
        "omg afd obj amd omg afd obj amd omg afd obj amd omg afd obj amd omg afd obj amd omg afd obj amd omg afd obj amd ",
        new Exception("Holy Maceral"),
    };

    foreach(var o in types)
    {
        Console.WriteLine("Size of {0} == {1}",o.GetType().Name,o.SizeOf());
    }
}
public static class ExtensionMethods
{
    public static int SizeOf(this object obj)
    {
        int size = 0;
        if(obj == null)
            return 0;
        Type type = obj.GetType();

        if(type.IsValueType)
        {
            return type.SizeOfType();
        }

        PropertyInfo[] info = type.GetProperties();
        foreach(PropertyInfo property in info)
        {
            if(property.GetIndexParameters().Length > 0)
            {
                var ip = property.GetIndexParameters().First();
                //Console.WriteLine(info);
                var len = (int)info.FirstOrDefault(x=>x.Name == "Length" || x.Name == "Count").GetValue(obj);
                for(var i = 0;i<len;i++)
                {
                    size += property.GetValue(obj,new object[1]{i}).SizeOf();
                }
            }
            else if(property.GetGetMethod().ReturnType.IsArray)
            {
                var arr = property.GetGetMethod().Invoke(obj,null);
                foreach(var a in (Array)arr)
                {
                    size+= a.SizeOf();
                }
            }
            else if(property.PropertyType.IsValueType)
            {
                var val = property.GetValue(obj,null);
                unsafe
                {
                    size += property.PropertyType.SizeOfType();
                }
            }
            else{
                size += property.GetValue(obj,null).SizeOf();
            }
        }
        return size;
    }

    public static int SizeOfType(this Type type)
    {
        if(type.IsValueType == false)
            throw new ArgumentException("type must be value type");

        return Marshal.SizeOf(type);
    }
}

输出

Size of Byte == 1
Size of Int16 == 2
Size of Int32 == 4
Size of Int64 == 8
Size of Double == 8
Size of Decimal == 16
Size of Single == 4
Size of String == 19
Size of String == 116
Size of Exception == 36

它并非100%完美,如果不进行一些调整,可能无法在每个对象上运行,但它应该能够确定哪个对象最具攻击性。