如何在内存中查找对象的大小
本文关键字:对象 查找 内存 | 更新日期: 2023-09-27 18:27:58
我知道这篇文章可能看起来重复,但我阅读了所有这些文章,并开发了一个测试主题的示例
在c中查找对象实例的大小(以字节为单位)#http://www.codeproject.com/Questions/177604/Size-of-a-class-in-c如何在内存中获取对象大小?使用C获取字段的大小(以字节为单位)#http://blogs.msdn.com/b/cbrumme/archive/2003/04/15/51326.aspx
我有一个类将任何属性或字段都抹掉,它是空的,只是为了测试它的大小。
[Serializable]
public class MemberStateModel
{
}
我创建了一个对象,并通过以下代码获得它的大小:
static void Main(string[] args)
{
MemberStateModel o = new MemberStateModel() {};
long size;
using (Stream s = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(s, o);
size = s.Length;
}
}
现在它的大小显示为159,我认为这意味着我的o大小是159k字节,但我认为这是不正确的方式,一个空物体不能有这样的大小,是真的吗?
这对我来说非常重要,因为我在会话中存储了一些用户的数据,如果这个大小随着站点中添加的用户而增加,我将需要更多的物理内存来处理我的web应用程序
在将对象放入本地内存缓存之前,我需要了解对象的内存消耗情况,因此我编写了一个扩展方法,该方法遍历对象的公共属性并汇总大小值。如果它是IEnumerable或Array,它将遍历项并计算它们的大小。这不是最好的方法,但对我来说已经足够好了,因为我的缓存没有比这更复杂的要求了。
public static class ObjectMemorySizeCalculator
{
static int OBJECT_SIZE = IntPtr.Size == 8 ? 24 : 12;
static int POINTER_SIZE = IntPtr.Size;
public static long GetMemorySize(this object obj)
{
long memorySize = 0;
Type objType = obj.GetType();
if (objType.IsValueType)
{
memorySize = Marshal.SizeOf(obj);
}
else if (objType.Equals(typeof(string)))
{
var str = (string)obj;
memorySize = str.Length * 2 + 6 + OBJECT_SIZE;
}
else if (objType.IsArray)
{
var arr = (Array)obj;
var elementType = objType.GetElementType();
if (elementType.IsValueType)
{
long elementSize = Marshal.SizeOf(elementType);
long elementCount = arr.LongLength;
memorySize += elementSize * elementCount;
}
else
{
foreach (var element in arr)
{
memorySize += element != null ? element.GetMemorySize() + POINTER_SIZE : POINTER_SIZE;
}
}
memorySize += OBJECT_SIZE;
}
else if (obj is IEnumerable)
{
var enumerable = (IEnumerable)obj;
foreach(var item in enumerable)
{
var itemType = item.GetType();
memorySize += item != null ? item.GetMemorySize() : 0;
if (itemType.IsClass)
memorySize += POINTER_SIZE;
}
memorySize += OBJECT_SIZE;
}
else if (objType.IsClass)
{
var properties = objType.GetProperties();
foreach (var property in properties)
{
var valueObject = property.GetValue(obj);
memorySize += valueObject != null ? valueObject.GetMemorySize() : 0;
if (property.GetType().IsClass)
memorySize += POINTER_SIZE;
}
memorySize += OBJECT_SIZE;
}
return memorySize;
}
BinaryFormatter告诉需要多少字节才能将类序列化为二进制。这与类在内存中的大小非常不同。例如,BinaryFormatter将有关类型的信息写入流中。
对象在内存中使用的大小不是在编译时定义的,而是在运行时定义的。因为JIT编译器决定最终布局。现在的问题是如何找出尺寸。虽然我有一个结构的解决方案(创建一个数组,进行指针运算),但我不知道如何为类找到它。一种解决方案是将类MemberStateModel
定义为一个结构,测量它,然后返回到一个类,假设它具有相同的大小。
您还可以通过将字段的大小计算为下限来估计大小(因为会出现填充)。如果您的类引用了其他类实例,那么估计起来几乎是不可能的。
首先,它不是159千字节,而是159字节。即使是空对象也会占用空间,这是因为BinaryFormatter还存储了一些元数据。本文提供了一些解释:http://www.codeproject.com/Articles/311944/BinaryFormatter-or-Manual-serializing.
要估计解决方案的内存复杂性,可以使用内存探查器。例如,我使用了这个,即使是试用版也很有用:http://www.jetbrains.com/profiler/.