爲什麼你寫的代碼運行內存這麼大?如何優化它們呢?
要想知道這個問題的答案首先應該知道怎樣估算對象和結構體的大小。
一、如何估算結構體的大小
結構是值類型,它的結構體的實例是存放在棧中或者堆中。結構體在內存中所佔的大小,就是其字段所佔的大小,但是,它的大小並不是所有字段大小相加,而是存在一個對齊的規則,在默認的對齊規則中,基本類型字段是按照自身大小對齊的,如byte是按1字節對齊。
struct A
{
byte a1;
}
如上面這個結構體的大小就是1字節,如果是下面這個:
struct A
{
byte a1;
int a2;
}
這個結構體所佔內存大小是8字節,因爲int是4字節對齊的,所以只能從第四個字節開始。
如果再添加一個字段:
struct A
{
byte a1;
int a2;
byte a3;
}
這個結構體大小是12,由於struct本身也要是對齊的,所以它的對齊規則是按照其中元素最大的對齊規則決定的。也就是說上面這個結構體要按照4字節對齊,不足4字節要補齊,所以是12個字節大小。
如果想要優化它的大小,可以調整順序如下:
struct A
{
byte a1;
byte a3;
int a2;
}
這個時候這個結構體所佔的大小就是8字節了。
二、如何估算類的大小
類是引用類型,它的對象實例存放在堆中,對象實例一定是會佔用堆內存的,而在棧中,保存的是實例的引用。對象在堆中分成3個區域,vtable、monitor和字段。其中vtable是類的共有數據,包含靜態變量和方法表,這個應該就是類本身所佔用的大小和具體的對象無關。monitor是線程同步用的,這2個指針分別佔用一個inptr.Size大小,字段是從第9個字節或17個字節開始的,字段的對齊規則和結構體的對齊規則相同,區別是Mono中對象的實例會把引用類型的引用放在最前面。一個對象實例的大小就是 inptr.Size *2+字段的大小。
通過調整字段的順序,也可以優化對象的大小。
在C#中還可以通過StructLayoutAttribute自定義類和結構體的對齊方式。
[StructLayout(LayoutKind, Sequential, Pack = 1)]
public struct A
{
byte a1;
int a2;
byte a3;
}
上面這個結構體強制按照1字節對齊,所以他的大小是6字節。但是這樣做可能會降低性能。
所以具體情況還是要具體分析,懂得了如何估算結構體和類的大小,就更容易知道該如何使用它們了。
歡迎關注公衆號:理想的鍵盤