c# - 以编程方式查找对象使用的内存

标签 c# memory profiling

有没有办法以编程方式准确地确定 c# 中对象使用的内存量?我不关心这个过程有多慢,所以左右运行 GC 是可以接受的(当然我更喜欢效率更高的东西)。

  • 序列化对象并查看结果长度似乎不是很准确(在对该方法的简单测试中,我看到一个整数返回值 54)。

  • 使用 GC.GetTotalMemory(true) 似乎会产生不一致的值,更不用说它们看起来太大了。

  • 使用 Marshal.SizeOf(object) 会产生准确的结果,但似乎只适用于原语。

如果这些方面没有可用的,另一种方法是根据使用的结构和所涉及的基元来计算大小。这也是可以接受的(虽然令人不安),但我需要知道计算对象开销等的正确方法。任何能向我展示如何做到这一点的文献都会很棒。

类似的SO问题(似乎都没有准确计算对象大小的具体方法):

How much memory does a C#/.NET object use?

How to get memory available or used in C#

How to get object size in memory?

sizeof() equivalent for reference types?

分析内存的工具(非编程方法):

http://www.microsoft.com/en-us/download/details.aspx?id=16273

Find out how much memory is being used by an object in C#?

最佳答案

另一个想法是有一个帮助类通过反射(reflect)对象并提取其所有数据成员并通过 sizeof() 收集所有字段大小来做到这一点,它会有点复杂但它是可以实现的

这个类将计算一个对象的实际大小,但我只测试了几次并且测试了一些对象,但我认为我会工作。

public class SizeHelper
{
    private static int GetTypeSizeArray(string typeName, object objValue)
    {
        switch (typeName)
        {
            case "System.Double[]":
                return sizeof(System.Double) * ((System.Double[]) objValue).Length ;
            case "System.Single[]":
                return sizeof(System.Single) * ((System.Single[])objValue).Length;
            case "System.Char[]":
                return sizeof(System.Char) * ((System.Char[])objValue).Length;
            case "System.Int16[]":
                return sizeof(System.Int16) * ((System.Int16[])objValue).Length;
            case "System.Int32[]":
                return sizeof(System.Int32) * ((System.Int32[])objValue).Length;
            case "System.Int64[]":
                return sizeof(System.Int64) * ((System.Int64[])objValue).Length;
            case "System.UInt16[]":
                return sizeof(System.UInt16) * ((System.UInt16[])objValue).Length;
            case "System.UInt32[]":
                return sizeof(System.UInt32) * ((System.UInt32[])objValue).Length;
            case "System.UInt64[]":
                return sizeof(System.UInt64) * ((System.UInt64[])objValue).Length;
            case "System.Decimal[]":
                return sizeof(System.Decimal) * ((System.Decimal[])objValue).Length;
            case "System.Byte[]":
                return sizeof(System.Byte) * ((System.Byte[])objValue).Length;
            case "System.SByte[]":
                return sizeof(System.SByte) * ((System.SByte[])objValue).Length;
            case "System.Boolean":
                return sizeof (System.Boolean)*((System.Boolean[]) objValue).Length;
            default:
                return 0;
        }
    }

    public static int GetSize(object obj)
    {
        Type t = obj.GetType();

        FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
        int size = 0;
        foreach (FieldInfo fieldInfo in fields)
        {
            if (fieldInfo.FieldType.BaseType.FullName.Equals("System.ValueType"))
            {
                size += GetTypeSize(fieldInfo.FieldType.FullName);
            }
            else if (fieldInfo.FieldType.BaseType.FullName.Equals("System.Array"))
            {
                var subObj = fieldInfo.GetValue(obj);
                if (subObj != null)
                    size += GetTypeSizeArray(fieldInfo.FieldType.FullName, subObj);
            }
            else if(fieldInfo.FieldType.FullName.Equals("System.String"))
            {
                var subObj = fieldInfo.GetValue(obj);
                if (subObj != null)
                {
                    size += subObj.ToString().Length*sizeof (System.Char);
                }
            }
            else
            {
                var subObj = fieldInfo.GetValue(obj);
                if (subObj != null)
                    size += GetSize(subObj);
            }
        }
        return size;
    }

    private static int GetTypeSize(string typeName)
    {
        switch (typeName)
        {
            case "System.Double":
                return sizeof(System.Double);
            case "System.Single":
                return sizeof(System.Single);
            case "System.Char":
                return sizeof(System.Char);
            case "System.Int16":
                return sizeof(System.Int16);
            case "System.Int32":
                return sizeof(System.Int32);
            case "System.Int64":
                return sizeof(System.Int64);
            case "System.UInt16":
                return sizeof(System.UInt16);
            case "System.UInt32":
                return sizeof(System.UInt32);
            case "System.UInt64":
                return sizeof(System.UInt64);
            case "System.Decimal":
                return sizeof(System.Decimal);
            case "System.Byte":
                return sizeof(System.Byte);
            case "System.SByte":
                return sizeof(System.SByte);
             case "System.Boolean":
                return sizeof (System.Boolean);
            default:
                return 0;
        }
    }
}

关于c# - 以编程方式查找对象使用的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12558928/

相关文章:

Linux 使用磁盘作为进程的 RAM

c++ - "scoping into"C++ 中类的头文件是否创建了它的实例?

go - 如何查看 runtime.futex 的来源?它只有 "System"作为父级

c++ - 如何测量代码片段的调用次数和运行时间

c# - Google API - Calendar API 正在运行,但 Gmail API 返回 '' unauthorized_client”

c# - 在 C# 中使用反射检测编译器生成的默认构造函数

c# - 如何使用 Windows 安装程序设置默认安装路径?

c# - Blazor WebAssembly 401 未经授权,即使我已获得授权

linux - 在Linux中检查可用内存的正确方法是什么

c++ - 在 Visual Studio 2008 PRO 中进行分析