簡體   English   中英

.NET 中的 String 和 Char 類型如何存儲在內存中?

[英]How are String and Char types stored in memory in .NET?

我需要存儲一個語言代碼字符串,例如“en”,它總是包含 2 個字符。

將類型定義為“String”還是“Char”更好?

private string languageCode;

對比

private char[] languageCode;

或者還有其他更好的選擇嗎?

這兩個如何存儲在內存中? 分配值時將為它們分配多少字節或位?

它們是如何存儲的

stringchar[]都存儲在堆上 - 所以存儲是相同的。 在內部,我會假設一個string只是char[]掩碼,其中包含許多額外的代碼以使其對您有用。

此外,如果您有很多重復的字符串,您可以使用Interning來減少這些字符串的內存占用。

更好的選擇

我更喜歡字符串 - 數據類型是什么以及您打算如何使用它立即變得更加明顯。 人們也更習慣於使用字符串,因此可維護性不會受到影響。 您還將從為您完成的所有樣板代碼中受益匪淺。 微軟也付出了很多努力來確保string類型不是一個性能豬。

分配大小

我不知道分配了多少,我相信字符串非常有效,因為它們只分配足夠的空間來存儲 Unicode 字符 - 因為它們是不可變的,所以這樣做是安全的。 如果不在新數組中分配空間,數組也無法調整大小,因此我再次假設它們只獲取所需的內容。

.NET 數組的開銷?

備擇方案

根據您的信息,只有 20 種語言代碼並且性能是關鍵,您可以聲明自己的枚舉以減少表示代碼所需的大小:

enum LanguageCode : byte
{
    en = 0,
}

這將只需要 1 個字節,而不是 4+ 兩個char (在一個數組中),但它確實將可用LanguageCode值的范圍限制在byte范圍內 - 這對於 20 個項目來說已經足夠了。

您可以使用sizeof()運算符查看值類型的sizeof()sizeof(LanguageCode) 枚舉只是引擎蓋下的底層類型,它們默認為int ,但正如您在我的代碼示例中所見,您可以通過“繼承”新類型來更改它。

簡短回答:使用字符串

長答案:

private string languageCode;

AFAIK 字符串存儲為長度前綴字符數組。 在堆上實例化一個 String 對象以維護這個原始數組。 但是 String 對象不僅僅是一個簡單的數組,它還支持基本的字符串操作,如比較、連接、子字符串提取、搜索等

盡管

private char[] languageCode;

將存儲為字符數組,即將在堆上創建一個 Array 對象,然后它將用於管理您的字符。 但它仍然有一個內部存儲的長度屬性,因此與字符串相比,沒有明顯的內存節省。 雖然大概 Array 比 String 更簡單,並且可能具有更少的內部變量,從而提供較低的內存占用(這需要驗證)。

但是 OTOH 你失去了對這個字符數組執行字符串操作的能力。 甚至像字符串比較這樣的操作現在也變得很麻煩。 長話短說使用字符串!

這兩個如何存儲在內存中? 分配值時將為它們分配多少字節或位?

.NET 中的每個實例存儲如下: 一個IntPtr大小的字段用於類型標識符; 另一個用於鎖定實例; 剩余部分是向上舍入為IntPtr大小的實例字段數據。 因此,在 32 位平台上,每個實例占用 8 個字節 + 字段數據。

這適用於stringchar[] 這兩者也將數據的長度存儲為 IntPtr 大小的整數,后跟實際數據。 因此,在 32 位平台上,兩個字符的string和兩個字符的char[]將占用 8+4+4 = 16 個字節。

當正好存儲兩個字符時,減少這種情況的唯一方法是將實際字符或包含字符的結構存儲在字段或數組中。 所有這些將只消耗 4 個字節的字符:

// Option 1
class MyClass
{
    char Char1, Char2;
}

// Option 2
class MyClass
{
    CharStruct chars;
}
...
struct CharStruct { public char Char1; public char Char2; }

MyClass最終將使用 8 個字節(在 32 位機器上)每個實例加上 4 個字節的字符。

// Option 3
class MyClass
{
    CharStruct[] chars;
}

這將使用 8 個字節的 MyClass 開銷,加上 4 個字節的chars引用,加上 12 個字節的數組開銷,加上數組中每個CharStruct 4 個字節。

如果您想准確存儲 2 個字符,並且要最有效地存儲,請使用結構:

struct Char2
{
 public char C1, C2;
}

使用此結構通常不會導致新的堆分配。 它只會擴大現有對象的大小(以盡可能小的數量)或消耗非常便宜的堆棧空間。

字符串確實具有一個指針長度的大小開銷,即 32 位進程為 4 個字節,64 位進程為 8 個字節。 但話又說回來,字符串提供的回報比字符數組多得多。

如果您的應用程序使用許多短字符串並且您不需要經常使用它們的字符串屬性和方法,那么您可能可以保護幾個字節的內存。 但是,如果要將其中任何一個用作字符串,則首先必須創建一個新的字符串實例。 我看不出這將如何幫助您確保足夠的內存值得麻煩。

String 只是在內部實現了一個 char 類型的索引器,我們可以說string只是等價於char[]類型,有很多額外的代碼使它對你有用,因此,就像一個數組,它總是存儲在堆上。

數組不能在不分配新空間的情況下進行操作,字符串也是如此,因此它是不可變的

String 實現IEnumerable<char>

值得注意的一點:當您將字符串傳遞給函數時,除非使用ref否則它是按值傳遞的

暫無
暫無

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

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