【发布时间】:2010-11-19 08:56:59
【问题描述】:
我想知道从“对象”继承并且没有字段/属性的对象占用多少内存?我猜方法不会。正确的 ?我说的是 .net 对象。
【问题讨论】:
-
好问题。我会说创建几百万个,然后查看前后的内存差异。除非有人已经这样做了。
-
这就是我问的原因。我需要知道具有数百万个对象的应用程序的内存使用情况。所以 32 位应用程序的答案是所有字段的大小 +8 字节。
我想知道从“对象”继承并且没有字段/属性的对象占用多少内存?我猜方法不会。正确的 ?我说的是 .net 对象。
【问题讨论】:
好的,因为 Andrew 和 Guffa 都给出了我认为是错误的答案...
所有对象都有 8 字节的开销(在 x86 上),但也有最小大小为 12 字节。我不知道为什么...但这意味着这两个类都每个实例占用 12 个字节:
public class OneField
{
private int field;
}
public class NoFields
{
}
测试:
using System;
public class OneField
{
private int field;
}
public class NoFields {}
public class Test
{
static void Main(string[] args)
{
int size = int.Parse(args[0]);
switch (args[1])
{
case "NoFields":
TestNoFields(size);
break;
case "OneField":
TestOneField(size);
break;
}
}
static void TestNoFields(int size)
{
NoFields[] array = new NoFields[size];
long start = GC.GetTotalMemory(true);
for (int i=0; i < size; i++)
{
array[i] = new NoFields();
}
long end = GC.GetTotalMemory(true);
GC.KeepAlive(array);
Console.WriteLine("Size per instance: {0}",
(end-start) / (double)size);
}
static void TestOneField(int size)
{
OneField[] array = new OneField[size];
long start = GC.GetTotalMemory(true);
for (int i=0; i < size; i++)
{
array[i] = new OneField();
}
long end = GC.GetTotalMemory(true);
GC.KeepAlive(array);
Console.WriteLine("Size per instance: {0}",
(end-start) / (double)size);
}
}
这很难看,因为我故意不使用任何泛型类型或任何其他可能导致问题的东西。一些测试运行:
>test 1000000 NoFields
Size per instance: 12.000024
>test 1000000 OneField
Size per instance: 12.000024
>test 1000 NoFields
Size per instance: 12
>test 1000 OneField
Size per instance: 12
(JITting 开销等解释了为什么这个数字并不总是一个精确的整数 - 因此我用浮点数进行除法。)
使用额外的 int 字段进行测试显示使用率高达 16,这证明它实际上在做一些明智的事情:)
【讨论】:
System.Object“继承”的确切信息有关。你是对的,虽然在 x86 上,第一个字段可以说是“免费的”,但没有 System.Object 的开销,前 3 个字段可能是免费的 :) 不过,为这个重要的区别 +1 给你。跨度>
一个对象有两个附加到它自己的数据的引用/指针。
因此,在 32 位系统上,对象需要 8 个字节,在 64 位系统上需要 16 个字节。
更正:
正如 Jon 所说,一个对象的最小大小是 12 个字节。到目前为止我发现的信息表明 GC 需要这个。
【讨论】:
引用类型会产生的唯一开销是类型对象指针的 4 个字节和同步块索引的 4 个字节。
所以总共有 8 个字节的开销。
【讨论】: