在 野田时光 v2中,我们正在向纳秒级分辨率移动。这意味着我们不能再使用一个8字节的整数来表示我们感兴趣的整个时间范围。这促使我调查 Noda Time (许多)结构的内存使用情况,这反过来又导致我发现 CLR 对齐决策中的一个小小的异常。
首先,我意识到这个 是是一个实现决策,默认行为可以随时改变。我意识到我 可以修改它使用 [StructLayout]
和 [FieldOffset]
,但我宁愿拿出一个解决方案,不要求,如果可能的话。
My core scenario is that I have a struct
which contains a reference-type field and two other value-type fields, where those fields are simple wrappers for int
. I had 希望 that that would be represented as 16 bytes on the 64-bit CLR (8 for the reference and 4 for each of the others), but for some reason it's using 24 bytes. I'm measuring the space using arrays, by the way - I understand that the layout may be different in different situations, but this felt like a reasonable starting point.
Here's a sample program demonstrating the issue:
using System;
using System.Runtime.InteropServices;
#pragma warning disable 0169
struct Int32Wrapper
{
int x;
}
struct TwoInt32s
{
int x, y;
}
struct TwoInt32Wrappers
{
Int32Wrapper x, y;
}
struct RefAndTwoInt32s
{
string text;
int x, y;
}
struct RefAndTwoInt32Wrappers
{
string text;
Int32Wrapper x, y;
}
class Test
{
static void Main()
{
Console.WriteLine("Environment: CLR {0} on {1} ({2})",
Environment.Version,
Environment.OSVersion,
Environment.Is64BitProcess ? "64 bit" : "32 bit");
ShowSize<Int32Wrapper>();
ShowSize<TwoInt32s>();
ShowSize<TwoInt32Wrappers>();
ShowSize<RefAndTwoInt32s>();
ShowSize<RefAndTwoInt32Wrappers>();
}
static void ShowSize<T>()
{
long before = GC.GetTotalMemory(true);
T[] array = new T[100000];
long after = GC.GetTotalMemory(true);
Console.WriteLine("{0}: {1}", typeof(T),
(after - before) / array.Length);
}
}
还有我笔记本电脑上的编译和输出:
c:\Users\Jon\Test>csc /debug- /o+ ShowMemory.cs
Microsoft (R) Visual C# Compiler version 12.0.30501.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.
c:\Users\Jon\Test>ShowMemory.exe
Environment: CLR 4.0.30319.34014 on Microsoft Windows NT 6.2.9200.0 (64 bit)
Int32Wrapper: 4
TwoInt32s: 8
TwoInt32Wrappers: 8
RefAndTwoInt32s: 16
RefAndTwoInt32Wrappers: 24
所以:
Int32Wrapper
字段打包在一起(TwoInt32Wrappers
的大小为8)int
字段打包在一起(RefAndTwoInt32s
的大小为16)Int32Wrapper
字段看起来都被填充/对齐到8字节(RefAndTwoInt32Wrappers
的大小为24)其他一些实验也得到了类似的结果:
object
而不是 string
没有帮助(我希望它是“任何引用类型”)int
字段仍然占4个字节,Int32Wrapper
字段占8个字节[StructLayout(LayoutKind.Sequential, Pack = 4)]
添加到视野中的每个结构并不会改变结果有没有人对此有什么解释(理想情况下是参考文档) ,或者有什么建议可以告诉 CLR,我希望字段打包为 没有,指定一个常量字段偏移量?