Joh*_*ith 24 .net c# memory arrays struct
有一个问题:
鉴于:
Run Code Online (Sandbox Code Playgroud)struct Point {int x; int y;} var p = new Point[3]如果我们使用64位处理器,将在堆栈和堆中分配多少字节的内存?
正确答案.Net是44.有人可以解释这个数字是如何出现的吗?
据我所知,p将占用堆栈中的8个字节x64.
并且我们有Int32每个结构的两个值,因此
堆中的p.Length * sizeof(Point)
3*8 = 24个字节用于数组.
这将是32个字节.在这种情况下剩下的12个字节是多少?
Tam*_*red 41
你对44字节的回答可能是一个混乱,指的是一个32位架构的数组.
在.Net (32位):
object包含4个字节用于同步(lock (obj)).object包含4个字节的类型令牌.array包含4个字节的长度.如你所说,指针是8个字节.
这个数组的24个字节本身就可以得到44个字节.
但是,这是32位的标题布局.
如您所见,以下代码的内存布局:
var p = new Point[3];
p[0] = new Point { x = 1, y = 2 };
p[1] = new Point { x = 3, y = 4 };
p[2] = new Point { x = 5, y = 6 };
var p2 = new Point[3];
p2[0] = new Point { x = 8, y = 8 };
p2[1] = new Point { x = 8, y = 8 };
p2[2] = new Point { x = 8, y = 8 };
Run Code Online (Sandbox Code Playgroud)
将会:
您也可以在内存布局中查看数字值.
在64位中,标题的每个字段占用8个字节,因此标题长度为24个字节,因此整个数组的长度为48个字节,变量指向数组:56个字节.
64位架构内存布局:
笔记:
如果您的数组没有四舍五入到8字节,则会发生多重对齐,但这样就不需要对齐.示例(两个1大小的int数组):
即使标题的长度字段是64位中的8个字节,它也比.NET允许的最大数组大小大,因此只能使用4 个字节.
请记住,这是一个实现细节,它可能会在CLR的实现/版本之间发生变化.
Voo*_*Voo 13
其中大部分纯粹是一个实现细节,可能会随着CLR的下一个版本而改变.
以x86或x64运行以下程序,您可以凭经验确定结构的大小:
struct Point { int x; int y; }
class Program
{
const int Size = 100000;
private static void Main(string[] args)
{
object[] array = new object[Size];
long initialMemory = GC.GetTotalMemory(true);
for (int i = 0; i < Size; i++)
{
array[i] = new Point[3];
}
long finalMemory = GC.GetTotalMemory(true);
GC.KeepAlive(array);
long total = finalMemory - initialMemory;
Console.WriteLine("Size of each element: {0:0.000} bytes",
((double)total) / Size);
}
}
Run Code Online (Sandbox Code Playgroud)
代码非常简单,但却被Jon Skeet无耻地偷走了.
如果您运行此操作,您将获得以下结果:
x86: 36 byte
x64: 48 byte
Run Code Online (Sandbox Code Playgroud)
在当前实现中,每个对象的大小与指针大小对齐,这意味着x86中的每个对象都是4字节对齐,并且在x64 8字节下(这绝对可以改变 - 例如Java中的HotSpot将所有内容对齐到8字节即使在x86下).
C#中的数组的长度有点特殊:虽然它们的长度为4字节,但在x64下它们还包括4字节的额外填充(vm/object.h:766包含有趣的部分).这很可能是为了保证实际字段的开始总是在x64下对齐8字节,这是在访问longs/double/pointer时获得良好性能所必需的(另一种方法是只为这些类型添加填充并专门化长度计算 - 不太可能值得额外的复杂性).
在x86上,对象头是8字节,数组开销是4字节,这给了我们36字节.
在x64上,对象头是16字节,数组开销是8字节.这给了我们24 + 24 = 48字节.
对于任何想要实际证明而不是关于标题大小和对齐的经验测试的人,您可以转到实际的源:这是coreclr的对象定义.查看从第178行开始的评论,该评论指出:
// The only fields mandated by all objects are
//
// * a pointer to the code:MethodTable at offset 0
// * a poiner to a code:ObjHeader at a negative offset. This is often zero. It holds information that
// any addition information that we might need to attach to arbitrary objects.
Run Code Online (Sandbox Code Playgroud)
您还可以查看实际代码,以查看这些指针是实际指针而不是DWORD或其他任何指针.
对齐对象大小的代码也在同一个文件中:
#define PTRALIGNCONST (DATA_ALIGNMENT-1)
#ifndef PtrAlign
#define PtrAlign(size) \
((size + PTRALIGNCONST) & (~PTRALIGNCONST))
#endif //!PtrAlign
Run Code Online (Sandbox Code Playgroud)
DATA_ALIGNMENT对于x86(vm/i386/cgencpu.h)和ARM(vm/arm/cgencpu.h)定义为4,对于x64(vm/amd64/cgencpu.h)定义为8.代码本身只是标准优化的"舍入到下一个倍数DATA_ALIGNMENT",假设数据对齐是2方法的幂.
| 归档时间: |
|
| 查看次数: |
2246 次 |
| 最近记录: |