簡體   English   中英

為什么一個類的數組比結構數組消耗的內存多20%?

[英]Why does an array of classes consume ~20% more memory than array of structs?

我正在制作一個2D平台游戲並代表我正在使用2D數組的瓦片,這些瓦片是具有位置,類型和各種標志字段的類。 當我將tile類中的class關鍵字更改為struct ,加載的地圖消耗的內存減少約20%。

我不知道這個動作的正確與否,我只是想知道為什么內存消耗的差異。

編輯:數字為1038 MB,瓦片為類,845 MB為結構(沒有大部分游戲數據)。

對象數組實際上是一個引用數組,對象存儲在堆上。

這意味着引用有4或8個字節的開銷(取決於x86或x64),然后堆上的每個對象都有8或16個字節的開銷。

在結構數組中,struct值直接存儲在數組中,因此不會產生額外的開銷。

因此,如果您的數據是例如48個字節,則額外的12個字節(在x86模式下)將是所用總內存的20%的開銷。

請注意,它們的使用方式也有所不同。 如果您移動切片或將其作為參數發送到方法,則在使用結構時將復制所有數據,但如果使用類,則僅復制引用。 如果你可以保持結構小於16個字節,性能差異很小,但如果它更大,你可以通過使用類來獲得更快的代碼。

每個對象都有一個8字節的頭,其中包含指向類型句柄和同步塊索引的指針,而結構是內聯分配的。 此外,您需要為正在使用的每個引用類型變量分配指針大小的引用。

本文將詳細介紹如何在運行時創建對象。

結構類型的存儲位置(變量,參數,數組元素或字段)包含其所有公共字段和私有字段的值,通常是連接的,但可能包含一些填充。 類類型的存儲位置保存對堆對象(可能為空)的引用(4-8個字節)。 堆對象保存8-16個字節的開銷,以及對象及其祖先持有的所有公共,受保護和私有字段的內容。

如果要存儲的內容是固定大小的值包,則應該使用具有公開字段的結構。 結構應該是不可變的概念可以追溯到C#編譯器將采用一段代碼的日子:

readonly Point Pt = new Point(3,4);
  void Yippie() { Pt.X += 5; }

並讓Yippie構造一個新的臨時Point ,將Pt復制到它,在該臨時實例上調用X屬性setter,然后丟棄它。 有人認為防止這種無意義的正確方法是不要讓編譯器說“抱歉 - 你不能在只讀結構變量上調用屬性設置器”,而是定義結構以便具有只讀屬性沒有二傳手。 已經做了正確的事情本來可以要求其將要發生變異的任何結構的方法或屬性this在他們的聲明中如此表示,禁止使用在只讀結構這樣的方法或屬性。

在屬性中包裝struct字段會影響性能,我建議不要使用它,除非需要強制執行struct invariants。 我也建議避免一個聲明結構readonly ,因為這樣聲明的結構將在任何領域的全面訪問任何時候都可以復制。

. 順便提一下,要注意可變類類型是一件重要的事情:可變類對象的狀態不僅包括其字段的內容,還包括它所 在某些情況下,這可能很有用。 通常,防止嚴重頭痛的唯一方法是讓持有可變對象引用的實體避免共享此類引用。 如果創建一個類類型的東西需要額外的工作來防止引用被濫用,這是一個好的跡象,有問題的類型應該是一個結構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM