最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

.net中如何以純二進制的形式在內存中繪制一個對象

 更新時間:2023年07月17日 09:07:29   作者:Artech  
這篇文章主要介紹了如何以純二進制的形式在內存中繪制一個對象,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一個對象總是映射一塊連續(xù)的內存序列(不考慮對象之間的引用關系),如果我們知道了引用類型實例的內存布局,以及變量引用指向的確切的地址,我們不僅可以采用純“二進制”的方式在內存“繪制”一個指定引用類型的實例,還可以修改某個變量的“值”指向它,還能直接通過改變二進制內容來更新實例的狀態(tài)。

一、引用類型實例的內存布局

從內存布局的角度來看,一個引用類型的實例由如下圖所示的三部分組成:ObjHeader + TypeHandle + Fields。前置的ObjHeader用來緩存哈希值和同步狀態(tài)(《如何將一個實例的內存二進制內容讀出來?》具有對此的詳細介紹),TypeHandle部分存儲類型對應方法表(Method Table)的地址,方法表可以視為針對類型的描述。也正是這部分內容的存在,運行時可以確定任何一個實例的真實類型,所以我們才說引用類型的實例是自描述(Self Describing)的。Fields用于存儲實例每個字段的內容。

對于32位(x86)的機器來說,ObjHeader 和 TypeHandle的長度都是4字節(jié)。如果是64位(x64)的機器,用于存儲方法表地址的TypeHandle 需要8個字節(jié)來存儲,但是ObjHeader 依然是4個直接??紤]到內存對齊,需要前置4個字節(jié)的Padding。對于一個不為null的應用類型變量來說,它存儲的是實例的內存地址。但是這個地址并不是實例所在內存的“首地址(ObjHeader)”,而是TypeHandle部分的地址。

二、以二進制的形式創(chuàng)建對象

既然我們已經知道了引用類型實例的內存布局,也知道了引用指向的確切的地址,我們不僅可以采用純“二進制”的方式在內存“繪制”一個指定引用類型的實例,還可以修改某個變量的“值”指向它。具體的實現(xiàn)體現(xiàn)在如下所示的Create方法中,該方法根據指定的屬性值創(chuàng)建一個Foobar對象。除了用來提供兩個屬性值的foo、bar參數(shù)之外,它還通過輸出參數(shù)bytes返回整個實例的字節(jié)序列。

var foobar = Create(1, 2, out var bytes);
Debug.Assert(foobar.Foo == 1);
Debug.Assert(foobar.Bar == 2);
static unsafe Foobar Create(int foo, int bar, out byte[] bytes)
{
    Foobar foobar = null!;
    bytes = new byte[24];
    BinaryPrimitives.WriteInt64LittleEndian(bytes.AsSpan(8), typeof(Foobar).TypeHandle.Value.ToInt64());
    BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(16), foo);
    BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(20), bar);
    Unsafe.Write(Unsafe.AsPointer(ref foobar), new IntPtr(Unsafe.AsPointer(ref bytes[8])));
    return foobar;
}
public class Foobar
{
    public int Foo { get; set; }
    public int Bar { get; set; }
}

根據上述針對內存布局的介紹,我們知道任何一個Foobar實例在x64機器中都映射位一段連續(xù)的24字節(jié)內存,所以Create方法創(chuàng)建了一個長度位24的字節(jié)數(shù)組。我們保持ObjHeader為空,所以我們從第8(zero based)個字節(jié)開始寫入Foobar類型對應TypeHandle的值(8字節(jié)),然后將指定的數(shù)據成員的值(int類型占據4個字節(jié))填充到最后8個字節(jié)(由于兩個字段的類型均為int,所以不需要添加額外的“留白”來確保內存對齊)。自此我們將“憑空”在內存中“繪制”了一個Foobar對象。由于x86機器采用“小端字節(jié)序”,所以二進制的寫入最終是通過調用BinaryPrimitives的WriteInt32/64LittleEndian方法來完成的。

接下來我們定義一個Foobar類型的變量,并讓它指向這個繪制的Foobar對象。我們在上面說過,它指向的不是實例內存的首字節(jié),而是TypleHandle部分。對于我們的例子來說,它指向的就是我們創(chuàng)建的字節(jié)數(shù)組的第8(zero based)的元素。針對變量內容(目標對象的地址)的改寫是通過調用Unsafe的靜態(tài)方法Write實現(xiàn)的。我們的演示程序調用了Create創(chuàng)建了一個Foo和Bar屬性分別為1和2的Foobar對象,并得到它真正映射在內存中的字節(jié)序列。

三、字節(jié)數(shù)組與實例狀態(tài)的同一性

對于我們定義的Create方法來說,由于通過輸出參數(shù)返回的字節(jié)數(shù)字就是返回的Foobar對象在內存中的映射,所以Foobar的狀態(tài)(Foo和Bar屬性)發(fā)生改變后,字節(jié)數(shù)組的內容也會發(fā)生改變。這一點可以通過如下的程序來驗證。

var foobar = Create(1, 1, out var bytes);
Console.WriteLine(BitConverter.ToString(bytes));
foobar.Foo = 255;
foobar.Bar = 255;
Console.WriteLine(BitConverter.ToString(bytes));

輸出結果

00-00-00-00-00-00-00-00-D8-11-30-17-F9-7F-00-00-01-00-00-00-01-00-00-00
00-00-00-00-00-00-00-00-D8-11-30-17-F9-7F-00-00-FF-00-00-00-FF-00-00-00

既然返回的字節(jié)數(shù)據和Foobar對象具有同一性,我們自然也可以按照如下的方式通過修改字節(jié)數(shù)組的內容來到達改變實例狀態(tài)的目的。

var foobar = Create(1, 1, out var bytes);
Debug.Assert(foobar.Foo == 1);
Debug.Assert(foobar.Bar == 1);
BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(16), 255);
BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(20), 255);
Debug.Assert(foobar.Foo == 255);
Debug.Assert(foobar.Bar == 255);

四、ObjHeader針對哈希被同步狀態(tài)的緩存

我們可以進一步利用這種方式驗證實例的ObjHeader針對哈希值和同步狀態(tài)的緩存。如下面的代碼片段所示,我們調用Create創(chuàng)建了一個Foobar對象并將得到的字節(jié)數(shù)組打印出來。然后我們調用其GetHashCode方法觸發(fā)哈希值的計算,并再次打印字節(jié)數(shù)組。接下來我們創(chuàng)建一個新的Foobar對象,分別對它進行加鎖和解鎖狀態(tài)打印字節(jié)數(shù)組。

var foobar = Create(1, 2, out var bytes);
Console.WriteLine($"{BitConverter.ToString(bytes)}[Original]");
foobar.GetHashCode();
Console.WriteLine($"{BitConverter.ToString(bytes)}[GetHashCode]");
foobar = Create(1, 2, out bytes);
lock (foobar)
{
    Console.WriteLine($"{BitConverter.ToString(bytes)}[Enter lock]");
}
Console.WriteLine($"{BitConverter.ToString(bytes)}[Exit lock]");

從如下所示的輸出結果可以看出,在GetHashCode方法調用和被“鎖住”之后,承載Foobar對象的ObjHeader字節(jié)(4-7字節(jié))都發(fā)生了改變,實際上運行時就是利用它來存儲計算出的哈希值和同步狀態(tài)。至于ObjHeader具體的字節(jié)布局,我的另一篇文章《如何將一個實例的內存二進制內容讀出來?》提供了系統(tǒng)的說明。

00-00-00-00-00-00-00-00-90-1C-30-17-F9-7F-00-00-01-00-00-00-02-00-00-00[Original]
00-00-00-00-C7-D5-9F-0D-90-1C-30-17-F9-7F-00-00-01-00-00-00-02-00-00-00[GetHashCode]
00-00-00-00-01-00-00-00-90-1C-30-17-F9-7F-00-00-01-00-00-00-02-00-00-00[Enter lock]
00-00-00-00-00-00-00-00-90-1C-30-17-F9-7F-00-00-01-00-00-00-02-00-00-00[Exit lock]

到此這篇關于以純二進制的形式在內存中繪制一個對象的文章就介紹到這了,更多相關二進制形式繪制一個對象內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • ASP.NET私有構造函數(shù)用法分析

    ASP.NET私有構造函數(shù)用法分析

    這篇文章主要介紹了ASP.NET私有構造函數(shù)用法,較為詳細的分析了ASP.NET中私有構造函數(shù)的特性及具體用法,需要的朋友可以參考下
    2014-11-11
  • 在ASP.NET中讀寫XML數(shù)據的多種方法

    在ASP.NET中讀寫XML數(shù)據的多種方法

    在ASP.NET日常開發(fā)中,XML(可擴展標記語言)是一種常用的數(shù)據交換格式,它被廣泛用于配置文件、數(shù)據傳輸和Web服務等場景,在.NET框架中,提供了多種類和方法來讀寫XML數(shù)據,以下是對ASP.NET中讀寫XML的詳解,需要的朋友可以參考下
    2025-01-01
  • asp.net下PageMethods使用技巧

    asp.net下PageMethods使用技巧

    ASP.net AjAX中的PageMethods可以將靜態(tài)頁方法添加到 ASP.NET 頁中并將其用作 Web 方法。然后,無需創(chuàng)建單獨的 .asmx 文件即可從該頁中的腳本調用這些方法,就好像這些方法是 Web 服務的一部分。特別是在一些交互流程不復雜而調用次數(shù)和方法又比較多的情況下更為方便。因為PageMethods不需要我們再添加另外的WEB服務或Page來處理請求。
    2008-03-03
  • asp.net中Repeart選中整行操作實例

    asp.net中Repeart選中整行操作實例

    這篇文章主要介紹了asp.net中Repeart選中整行操作的方法,實例分析了asp.net中Repeart的使用技巧,需要的朋友可以參考下
    2015-01-01
  • Entity Framework Core實現(xiàn)軟刪除與查詢過濾器

    Entity Framework Core實現(xiàn)軟刪除與查詢過濾器

    這篇文章介紹了Entity Framework Core實現(xiàn)軟刪除與查詢過濾器的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • ASP.NetCore使用Swagger實戰(zhàn)

    ASP.NetCore使用Swagger實戰(zhàn)

    這篇文章主要介紹了ASP.NetCore使用Swagger實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • asp.net中Timer無刷新定時器的實現(xiàn)方法

    asp.net中Timer無刷新定時器的實現(xiàn)方法

    這篇文章主要介紹了asp.net中Timer無刷新定時器的實現(xiàn)方法,是一個非常具有實用價值的技巧,需要用到Ajax技術,需要的朋友可以參考下
    2014-08-08
  • ASP.NET中Validation驗證控件正則表達式特殊符號的說明

    ASP.NET中Validation驗證控件正則表達式特殊符號的說明

    本文介紹asp.net中RegularExpressionValidator控件中的幾種特殊字符串使用規(guī)則,并做了代碼演示,希望對大家有所幫助。
    2016-04-04
  • VS2015正式版安裝教程

    VS2015正式版安裝教程

    這篇文章主要為大家詳細介紹了VS2015正式版安裝教程,初次體驗VS2015正式版,安裝詳細過程分給大家,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • asp.net membership 密碼重設

    asp.net membership 密碼重設

    membership 重設密碼
    2008-12-12

最新評論

合阳县| 抚松县| 噶尔县| 休宁县| 慈利县| 樟树市| 濮阳市| 如东县| 庆安县| 融水| 汉寿县| 杂多县| 邻水| 本溪市| 伊宁县| 肇庆市| 天水市| 都江堰市| 古丈县| 三河市| 柘城县| 曲周县| 栾川县| 夏河县| 昌乐县| 罗甸县| 盘锦市| 宁陵县| 稻城县| 通江县| 彝良县| 新龙县| 丘北县| 玛沁县| 亚东县| 容城县| 同江市| 定结县| 藁城市| 永登县| 小金县|