亚洲乱色熟女一区二区三区丝袜,天堂√中文最新版在线,亚洲精品乱码久久久久久蜜桃图片,香蕉久久久久久av成人,欧美丰满熟妇bbb久久久

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

.NET中的數(shù)組在內(nèi)存中如何布局?

freeflydom
2023年11月27日 11:15 本文熱度 1560

總的來說,.NET的值類型和引用類型都映射一段連續(xù)的內(nèi)存片段。不過對(duì)于值類型對(duì)象來說,這段內(nèi)存只需要存儲(chǔ)其字段成員,而對(duì)應(yīng)引用類型對(duì)象,還需要存儲(chǔ)額外的內(nèi)容。就內(nèi)存布局來說,引用類型有兩個(gè)獨(dú)特的存在,一個(gè)是字符串,另一個(gè)就是數(shù)組。我在《你知道.NET的字符串在內(nèi)存中是如何存儲(chǔ)的嗎?》一文中對(duì)字符串的內(nèi)存布局作了詳細(xì)介紹,今天我們來聊聊數(shù)組類型的內(nèi)存布局。

一、引用類型布局
二、數(shù)組類型布局
三、值類型數(shù)組
四、引用類型數(shù)組

一、引用類型布局

但是對(duì)于引用類型對(duì)象,除了存儲(chǔ)其所有字段成員外,還需要存儲(chǔ)一個(gè)Object Header和TypeHandle,前者可以用來存儲(chǔ)Hash值,也可以用來存儲(chǔ)同步狀態(tài);后者存儲(chǔ)的是目標(biāo)類型方法表的地址(詳細(xì)介紹可以參考我的文章《如何計(jì)算一個(gè)實(shí)例占用多少內(nèi)存?》、《如何將一個(gè)實(shí)例的內(nèi)存二進(jìn)制內(nèi)容讀出來?》。

如下圖所示,對(duì)于32位(x86)系統(tǒng),Object Header和TypeHandle各占據(jù)4個(gè)字節(jié);但是對(duì)于64位(x64)來說,存儲(chǔ)方法表指針的TypeHandle自然擴(kuò)展到8個(gè)字節(jié),但是Object Header依然是4個(gè)字節(jié),為了確保TypeHandle基于8字節(jié)的內(nèi)存對(duì)齊,所以會(huì)前置4個(gè)字節(jié)的“留白(Padding)”。

順便說一下,即使沒有定義任何的字段成員,運(yùn)行時(shí)依然會(huì)使用一個(gè)“指針寬度(IntPtr.Size)”的存儲(chǔ)空間(上圖中的Payload),所以x86/x64系統(tǒng)中一個(gè)引用類型對(duì)象至少占據(jù)12/24字節(jié)的內(nèi)存。除此之外,所謂對(duì)象的引用并不是指向這段內(nèi)存的起始位置,而是指向TypeHandle的地址。

二、數(shù)組類型布局

既然數(shù)組是引用類型,它自然按照上面的方式進(jìn)行內(nèi)存布局。它依然擁有4字節(jié)的Object Header,TypeHandle部分存儲(chǔ)的是數(shù)組類型自身的方法表地址。其荷載內(nèi)容(Payload)采用如下的布局:前置4個(gè)字節(jié)以UInt32的形式存儲(chǔ)數(shù)組的長度,后面依次存儲(chǔ)每個(gè)數(shù)組元素的內(nèi)容。對(duì)于64位(x64)來說,為了確保數(shù)組元素的內(nèi)存對(duì)齊,兩者之間具有4個(gè)字節(jié)的Padding。

三、值類型數(shù)組

對(duì)于值類型的數(shù)組,Payload部分直接存儲(chǔ)元素自身的值。如下程序演示了如何將一個(gè)字節(jié)數(shù)組對(duì)象在內(nèi)存中的字節(jié)序列讀出來。如代碼片段所示,GetArray方法根據(jù)上述的內(nèi)存布局計(jì)算出一個(gè)數(shù)組對(duì)象占據(jù)的字節(jié)數(shù),并創(chuàng)建出對(duì)應(yīng)的字節(jié)數(shù)據(jù)來存儲(chǔ)數(shù)組對(duì)象的字節(jié)內(nèi)容。我們?cè)谏厦嬲f過,一個(gè)數(shù)組變量指向的是目標(biāo)對(duì)象TypeHandle部分的地址,所以我們需要前移一個(gè)指針寬度才能得到內(nèi)存的起始位置。我們最終利用起始位置和字節(jié)數(shù),將承載數(shù)組自身對(duì)象的字節(jié)讀出來存放到預(yù)先創(chuàng)建的字節(jié)數(shù)組中。

var array = new byte[] { byte.MaxValue, byte.MaxValue, byte.MaxValue };
Console.WriteLine($"Array: {BitConverter.ToString(GetArray(array))}");
Console.WriteLine($"TypeHandle of Byte[]: {BitConverter.ToString(GetTypeHandle<byte[]>())}");unsafe static byte[] GetArray<T>(T[] array)
{
    var size = IntPtr.Size // Object header + Padding
     + IntPtr.Size // TypeHandle
     + IntPtr.Size // Length + Padding
     + Unsafe.SizeOf<T>() * array.Length // Elements
        ;
    var bytes = new byte[size];
    var pointer = Unsafe.AsPointer(ref array);
    var head = *(IntPtr*)pointer - IntPtr.Size;
    Marshal.Copy(head, bytes, 0, size);    return bytes;
}
unsafe static byte[] GetTypeHandle<T>() => BitConverter.GetBytes(typeof(T).TypeHandle.Value);

為了進(jìn)一步驗(yàn)證數(shù)組對(duì)象每個(gè)部分的內(nèi)容,我們還定義了GetTypeHandle<T>方法讀取目標(biāo)類型TypeHandle的值(方法表地址)。在演示程序中,我們創(chuàng)建了一個(gè)長度位3的字節(jié)數(shù)組,并將三個(gè)數(shù)組元素的值設(shè)置位byte.MaxValue。我們將承載這個(gè)數(shù)組的字節(jié)序列和字節(jié)數(shù)組類型的TypeHandle的值打印出來。

Array: [00-00-00-00-00-00-00-00]-[E0-6A-0D-01-FF-7F-00-00]-[03-00-00-00]-00-00-00-00-[FF-FF-FF]
TypeHandle of Byte[]: E0-6A-0D-01-FF-7F-00-00

如上所示的輸出結(jié)果驗(yàn)證了數(shù)組對(duì)象的內(nèi)存布局。由于演示機(jī)器為64位系統(tǒng),所以前8個(gè)字節(jié)表示Object Header(4字節(jié))和Padding(4字節(jié))。中間高亮的8個(gè)字節(jié)正好與字節(jié)數(shù)組類型的TypeHandle的值一致。后面4個(gè)字節(jié)(03-00-00-00)表示字節(jié)的長度(3),緊隨其后的4個(gè)字節(jié)位Padding。最后的內(nèi)容正好是三個(gè)數(shù)組元素的值(FF-FF-FF)。

四、引用類型數(shù)組

對(duì)于引用類型的數(shù)組,其每個(gè)數(shù)組元素存儲(chǔ)是元素對(duì)象的地址,下面的程序驗(yàn)證了這一點(diǎn)。如代碼片段所示,我們定義了GetAddress<T>方法得到指定變量指向的目標(biāo)地址,并將其轉(zhuǎn)換成返回的字節(jié)數(shù)組。演示程序創(chuàng)建了一個(gè)包含三個(gè)元素的字符串?dāng)?shù)組,我們將承載數(shù)組對(duì)象的字節(jié)序列和作為數(shù)組元素的三個(gè)字符串對(duì)象的地址打印出來。

var s1 = "foo";
var s2 = "bar";
var s3 = "baz";
var array = new string[] { s1, s2, s3 };
Console.WriteLine($"Array: {BitConverter.ToString(GetArray(array))}");
Console.WriteLine($"element 1: {BitConverter.ToString(GetAddress(ref s1))}");
Console.WriteLine($"element 2: {BitConverter.ToString(GetAddress(ref s2))}");
Console.WriteLine($"element 3: {BitConverter.ToString(GetAddress(ref s3))}");unsafe static byte[] GetAddress<T>(ref T value)
{
    var address = *(IntPtr*)Unsafe.AsPointer(ref value);    return  BitConverter.GetBytes(address);
}

從如下的代碼片段可以看出,在承載數(shù)組對(duì)象的字節(jié)序列中,最后的24字節(jié)正好是三個(gè)字符串的地址。

Array: 00-00-00-00-00-00-00-00-48-E9-5E-03-FF-7F-00-00-03-00-00-00-00-00-00-00-E0-EF-40-73-72-02-00-00-00-F0-40-73-72-02-00-00-20-F0-40-73-72-02-00-00
element 1: E0-EF-40-73-72-02-00-00
element 2: 00-F0-40-73-72-02-00-00
element 3: 20-F0-40-73-72-02-00-00


查看原文


該文章在 2023/11/27 11:15:11 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved