在Noda Time v2中,我们将转向纳秒分辨率。这意味着我们不能再使用8字节整数来表示我们感兴趣的整个时间范围。这促使我调查Noda Time的(许多)结构的内存使用情况,这反过来又让我发现了CLR对齐决策中的一个小小的奇怪之处。
首先,我意识到这是一个实现决策,默认行为随时可能改变。我意识到我可以使用[StructLayout]
和[FieldOffset]
修改它,但如果可能的话,我宁愿提出一个不需要这样做的解决方案。
我的核心场景是,我有一个包含一个引用类型字段和另外两个值类型字段的struct
,其中这些字段是int
的简单包装器。我曾希望在64位CLR上将其表示为16个字节(8个用于引用,4个用于其他引用),但由于某种原因,它使用了24个字节。顺便说一句,我是用数组来测量空间的--我知道在不同的情况下布局可能会不同,但这感觉像是一个合理的起点。
下面是一个演示该问题的示例程序:
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
有一个引用类型字段的大小)这两个字段,每个Int32Wrapper
字段看起来都被填充/对齐到8个字节。(RefAndTwoInt32Wrappers
的大小为24。)在调试器(但仍是发布版本)中运行相同代码的其他一些实验也产生了类似的结果:
object
而不是string
没有帮助(我期望它是“任何引用类型”)<代码>H132使用泛型结构作为引用的包装器没有帮助<代码>H233<代码>H134如果我继续添加字段(为简单起见),<代码>D35字段仍然是4个字节,和Int32Wrapper
字段的大小为8个字节,
[StructLayout(LayoutKind.Sequential, Pack = 4)]
添加到可见的每个结构中不会更改结果有没有人对此有任何解释(最好是参考文档),或者我如何才能向CLR提示我希望在不指定常量字段偏移量的情况下打包字段?
https://stackoverflow.com/questions/24742325
复制相似问题