一套關(guān)于 內(nèi)存對齊 的C#面試題,做錯的人很多!
這是一套朋友公司的面試題,挺有意思分享一下。
題目:判斷下面的 Location1 和 Location2 的結(jié)構(gòu)體大小各是多少?
????public?struct?Location1
????{
????????public?int?X;
????????public?int?Y;
????????public?long?Z;
????}
????public?struct?Location2
????{
????????public?int?X;
????????public?long?Y;
????????public?int?Z;
????}
據(jù)反饋 90% 的人說一樣大,畢竟從代碼看僅僅做了一次 Y 和 Z 順序的交換,那真的是這樣嗎?可以用 windbg 調(diào)試下就好了。
完整代碼代碼如下:
namespace?ConsoleApp2
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????Location1?location1;
????????????Location2?location2;
????????????location1.X?=?10;
????????????location1.Y?=?11;
????????????location1.Z?=?12;
????????????location2.X?=?10;
????????????location2.Y?=?11;
????????????location2.Z?=?12;
????????????Debugger.Break();
????????}
????}
????public?struct?Location1
????{
????????public?int?X;
????????public?int?Y;
????????public?long?Z;
????}
????public?struct?Location2
????{
????????public?int?X;
????????public?long?Z;
????????public?int?Y;
????}
}
windbg 輸出結(jié)果如下:
0:000>?!clrstack?-a
OS?Thread?Id:?0x1750?(0)
????????Child?SP???????????????IP?Call?Site
00000000007fef68?00007ff9a84b9ad2?[HelperMethodFrame:?00000000007fef68]?System.Diagnostics.Debugger.BreakInternal()
00000000007ff050?00007ff989c0f5ee?System.Diagnostics.Debugger.Break()
00000000007ff0a0?00007ff92db5090b?ConsoleApp2.Program.Main(System.String[])?[D:\net5\ConsoleApp4\ConsoleApp2\Program.cs?@?26]
????PARAMETERS:
????????args?(0x00000000007ff110)?=?0x0000000003492cf0
????LOCALS:
????????0x00000000007ff0e0?=?0x0000000b0000000a
????????0x00000000007ff0c8?=?0x000000000000000a
00000000007ff2f8?00007ff98d086913?[GCFrame:?00000000007ff2f8]?
0:000>?dp?0x00000000007ff0c8
00000000`007ff0c8??00000000`0000000a?00000000`0000000c
00000000`007ff0d8??00000000`0000000b?0000000b`0000000a
00000000`007ff0e8??00000000`0000000c?00000000`007ff1f8
由于 棧 是從大到小生長的,所以用 dp 命令的時候, location2 是排在 location1 的前方,可以清楚的看到
location2: 000000000000000a 000000000000000c 000000000000000b很明顯它的size=3*8=24byte。location1: 0000000b0000000a 000000000000000c它的size=2*8=16byte
那為什么會差 8byte 呢?如果有熟悉 C/C++ 的朋友這時候應(yīng)該知道,其實(shí)就是 內(nèi)存對齊 ,為什么會出現(xiàn) 內(nèi)存對齊 ?我們知道,內(nèi)存是按照 byte 編址的,也就是一個地址存放一個byte,但cpu可不是這么玩的,它的一次讀取數(shù)是根據(jù) 地址總線 來的,目前我們 cpu 基本都是 64根數(shù)據(jù)總線,也就是一次性可以讀取 8個byte。
為了能夠讓 cpu 讀取效率更高,編譯器會適當(dāng)?shù)倪M(jìn)行 padding 操作,目的就是 按8 對齊,如果不對齊的話,cpu可能就會出現(xiàn)讀不全,也就導(dǎo)致必須至少兩次才能讀取完畢的情況,肯定會影響 cpu 效率的,還有一個原因是:有些機(jī)器必須對齊訪問,否則就會異常,所以編譯器為了更好的平臺移植性,只能對齊啦!
