问题描述
对于仅包含单个 byte
字段的结构,我希望该结构在内存中消耗 1 个字节。如果我创建一个该结构类型的数组,结果是一个准确的期望。将该结构用作类中的字段时,我也有同样的期望,但是,令我惊讶的是,每个字段都占用 IntPtr
的大小!我认为这只会由于将类填充到下一个字大小而发生,但无论如何似乎都是这种情况。这是为什么?
[编辑] 更新测量值
方法 | 平均 | 错误 | StdDev | Gen 0 | Gen 1 | 第 2 代 | 已分配 |
---|---|---|---|---|---|---|---|
AllocOneByte | 7.453 ns | 0.0885 ns | 0.0827 ns | 0.0076 | - | - | 24 B |
AllocTwoBytes | 8.394 ns | 0.0873 ns | 0.0816 ns | 0.0076 | - | - | 24 B |
AllocThreeBytes | 8.398 ns | 0.0559 ns | 0.0523 ns | 0.0076 | - | - | 24 B |
AllocOneByteWrapper | 8.373 ns | 0.0934 ns | 0.0873 ns | 0.0076 | - | - | 24 B |
AllocTwoByteWrappers | 9.815 ns | 0.1256 ns | 0.1175 ns | 0.0102 | - | - | 32 B |
AllocThreeByteWrappers | 11.274 ns | 0.1527 ns | 0.1429 ns | 0.0127 | - | - | 40 B |
AllocOneByteArray | 9.286 ns | 0.1609 ns | 0.1505 ns | 0.0102 | - | - | 32 B |
AllocTwoBytesArray | 9.396 ns | 0.1038 ns | 0.0920 ns | 0.0102 | - | - | 32 B |
AllocThreeBytesArray | 8.904 ns | 0.1183 ns | 0.1107 ns | 0.0102 | - | - | 32 B |
public class Benchmark
{
public class OneByte
{
public byte num;
}
public class TwoBytes
{
public byte num;
public byte num2;
}
public class ThreeBytes
{
public byte num;
public byte num2;
public byte num3;
}
public struct ByteWrapper
{
public byte num;
}
public class OneByteWrapper
{
public ByteWrapper num;
}
public class TwoByteWrappers
{
public ByteWrapper num;
public ByteWrapper num2;
}
public class ThreeByteWrappers
{
public ByteWrapper num;
public ByteWrapper num2;
public ByteWrapper num3;
}
[Benchmark]
public OneByte AllocOneByte()
{
return new OneByte();
}
[Benchmark]
public TwoBytes AllocTwoBytes()
{
return new TwoBytes();
}
[Benchmark]
public ThreeBytes AllocThreeBytes()
{
return new ThreeBytes();
}
[Benchmark]
public OneByteWrapper AllocOneByteWrapper()
{
return new OneByteWrapper();
}
[Benchmark]
public TwoByteWrappers AllocTwoByteWrappers()
{
return new TwoByteWrappers();
}
[Benchmark]
public ThreeByteWrappers AllocThreeByteWrappers()
{
return new ThreeByteWrappers();
}
[Benchmark]
public ByteWrapper[] AllocOneByteArray()
{
return new ByteWrapper[1];
}
[Benchmark]
public ByteWrapper[] AllocTwoBytesArray()
{
return new ByteWrapper[2];
}
[Benchmark]
public ByteWrapper[] AllocThreeBytesArray()
{
return new ByteWrapper[3];
}
}
[Edit2] 这与 Why isn't sizeof for a struct equal to the sum of sizeof of each member? 不同。这是关于使用小结构作为类中的字段。
解决方法
我在评论中意识到您说您对填充非常了解,但总的来说:这只是:填充。要进行更细粒度的控制并避免这种情况,您可以使用 [FieldOffset(...)]
(如果您需要避免不同类型的字段之间的填充)和 [StructLayout(...)]
(控制单个结构的定义大小)。从根本上说,ByteWrapper
被默认填充到字长。您可以使用 [StructLayout]
说服它不要这样做。
FWIW:对我来说,ByteWrapper
以 1 个字节出现,而 ThreeByteWrappers
以 8 个字节出现 - ThreeBytes
也是如此。
这当然不理想,但我设法通过将小结构字段包装在另一个结构中来解决这个问题。不幸的是,这只能保证适用于已知的结构体大小(因此使用泛型的结果可能出乎意料)。
public class Benchmark
{
public struct ByteWrapper
{
public byte num;
}
public class OneByteWrapper
{
public ByteWrapper num;
}
public class TwoByteWrappers
{
public struct SmallFields
{
public ByteWrapper num;
public ByteWrapper num2;
}
public SmallFields smallFields;
}
public class ThreeByteWrappers
{
public struct SmallFields
{
public ByteWrapper num;
public ByteWrapper num2;
public ByteWrapper num3;
}
public SmallFields smallFields;
}
[Benchmark]
public OneByteWrapper AllocOneByteWrapper()
{
return new OneByteWrapper();
}
[Benchmark]
public TwoByteWrappers AllocTwoByteWrappers()
{
return new TwoByteWrappers();
}
[Benchmark]
public ThreeByteWrappers AllocThreeByteWrappers()
{
return new ThreeByteWrappers();
}
}
方法 | 运行时 | 平均 | 错误 | StdDev | 比例 | Gen 0 | Gen 1 | 第 2 代 | 已分配 |
---|---|---|---|---|---|---|---|---|---|
AllocOneByteWrapper | .NET 4.8 | 9.747 ns | 0.0903 ns | 0.0844 ns | 1.00 | 0.0306 | - | - | 24 B |
AllocOneByteWrapper | .NET Core 5.0 | 9.787 ns | 0.1139 ns | 0.0951 ns | 1.00 | 0.0076 | - | - | 24 B |
AllocTwoByteWrappers | .NET 4.8 | 9.975 ns | 0.0655 ns | 0.0580 ns | 1.05 | 0.0306 | - | - | 24 B |
AllocTwoByteWrappers | .NET Core 5.0 | 9.474 ns | 0.1106 ns | 0.0981 ns | 1.00 | 0.0076 | - | - | 24 B |
AllocThreeByteWrappers | .NET 4.8 | 9.483 ns | 0.0535 ns | 0.0474 ns | 1.00 | 0.0306 | - | - | 24 B |
AllocThreeByteWrappers | .NET Core 5.0 | 9.446 ns | 0.1235 ns | 0.1031 ns | 1.00 | 0.0076 | - | - | 24 B |