我需要存儲一個語言代碼字符串,比如「en」,它總是包含2個字符。如何在.NET中的內存中存儲字符串和字符類型?
定義類型爲「String」還是「Char」更好?
private string languageCode;
VS
private char[] languageCode;
還是有另一種更好的選擇嗎?
這些2如何存儲在內存中?在賦值時,會爲它們分配多少字節或比特?
我需要存儲一個語言代碼字符串,比如「en」,它總是包含2個字符。如何在.NET中的內存中存儲字符串和字符類型?
定義類型爲「String」還是「Char」更好?
private string languageCode;
VS
private char[] languageCode;
還是有另一種更好的選擇嗎?
這些2如何存儲在內存中?在賦值時,會爲它們分配多少字節或比特?
他們是如何存儲
無論是string
和char[]
被保存在堆上 - 所以存儲是一樣的。在內部,我會假設string
僅僅是char[]
的覆蓋物,很多的額外代碼,以使其對您有用。
此外,如果您有很多重複字符串,則可以使用Interning來減少這些字符串的內存佔用量。
更好的選擇
我贊成字符串 - 它立即是更加明顯的數據類型是什麼,你打算如何使用它。人們也更習慣於使用字符串,因此可維護性不會受到影響。您將從所有爲您完成的樣板代碼中受益匪淺。微軟還投入了大量精力確保string
類型不是一個性能高峯。
分配大小
我不知道有多少是分配的,我相信字符串是在非常有效,他們只分配足夠的存儲Unicode字符 - 因爲他們是不可變的可以安全地做到這一點。如果不在新數組中分配空間,數組也不能被調整大小,所以我再次假設他們只抓取他們需要的數據。
替代
根據您的信息,目前只有20個語言代碼和性能是關鍵,你可以聲明自己的枚舉,以減少代表編碼要求的尺寸:
enum LanguageCode : byte
{
en = 0,
}
這將只需要1個字節,而不是至4+兩個char
(在陣列中),但它確實限制availabl的範圍e LanguageCode
的值在byte
的範圍內 - 對於20個項目而言足夠大。
您可以使用sizeof()
運算符:sizeof(LanguageCode)
來查看值類型的大小。枚舉不過是引擎蓋下的底層類型,它們默認爲int
,但正如您在我的代碼示例中看到的那樣,您可以通過「繼承」新類型來更改它。
你不明確實習在.NET中的字符串;他們只是通過單純的聲明而隱含地爲你實習。另外,字符串和字符數組在.Net中是非常不同的,因爲字符數組在堆中是可變結構,甚至是堆棧,具體取決於你如何聲明它們,而字符串是不可變的,並且作爲鏈接到註釋的文章,構建建立和建立在實習生池中,而不是常規的.Net Framework內存 - 這意味着它們可能非常浪費。 –
@ChrisMoschini並非所有的字符串都被禁用。文字是實習的,但別無其他。如果您輸入一個字符串,請從資源文件或其他未被限制的源文件中讀取。你必須手動實習。有趣的是,我的答案甚至沒有聲明。 –
這取決於如何編寫代碼 - 例如,如果它正在搜索代碼中聲明的一串字符串位,那麼最終會得到一堆字符串。但是,重要的性能問題是當你知道你不需要它們時在堆上拋出大量不必要的中間字符串 - 單個字符數組總是會更便宜地記憶,如果你編寫類似於正則表達式的內部,更便宜的CPU。 .Net中使用較少的內存也意味着較少的GC,這也有另一個CPU好處。 –
如果你想存儲恰好2個字符,並最有效地做到這一點,使用結構:
struct Char2
{
public char C1, C2;
}
採用這種結構一般不會造成新的堆分配。它只會升高現有對象(儘可能少的數量)或消耗非常便宜的堆棧空間。
堆分配將完全取決於*你在哪裏聲明結構。它只會在方法/屬性中聲明的堆棧上。在課堂內部,它將與堆中的其他成員一起在堆中。 –
它不會導致* new *分配。它只會升高現有的對象(儘可能少的量)。 – usr
是的,但堆分配通常非常快,最初不應該擔心。也就是說,'struct LanguageCode'的結構是一個不錯的選擇。 –
簡短的回答:使用字符串
龍答:
private string languageCode;
AFAIK字符串存儲作爲一個字符長度前綴陣列。一個String對象在堆上實例化以維護這個原始數組。但字符串對象是比簡單的陣列就能夠像比較基本的字符串操作得多,級聯,子串的提取,搜索等
雖然
private char[] languageCode;
將被存儲爲字符數組,即Array對象將在堆上創建,然後它將用於管理你的角色。但它仍然有一個內部存儲的長度屬性,所以與字符串相比,內存沒有明顯的節省。雖然大概是一個數組比字符串簡單,並且可能會有較少的內部變量,從而提供較低的內存足跡(這需要驗證)。
但是OTOH你放棄了對char數組執行字符串操作的能力。即使像字符串比較這樣的操作現在也變得很麻煩。所以長話短說使用一個字符串!
這些2如何存儲在內存中?在賦值時,會爲它們分配多少字節或比特?在.NET
每實例存儲爲如下:對於類型標識符的一個尺度的IntPtr
字段;還有一個用於鎖定實例;其餘的實例字段數據四捨五入爲IntPtr
大小。因此,在32位平臺上,每個實例佔用8個字節+字段數據。
這適用於string
和char[]
。這兩者都將數據的長度存儲爲一個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個字節。
有趣。你從哪裏得到這些信息? – kristianp
@kristianp大部分信息來自以下MSDN文章:https://msdn.microsoft.com/en-us/magazine/cc163791.aspx(向下滾動到圖6) –
字符串確實有一個指針長度的開銷,即對於32位進程是4字節,對於64位進程是8字節。但是再一次,字符串提供了比char數組更多的回報。
如果您的應用程序使用很多短字符串,並且不需要經常使用字符串屬性和方法,那麼您可能可以安全地存儲幾個字節的內存。但是如果你想使用它們中的任何一個作爲字符串,你首先必須創建一個新的字符串實例。我看不出這將如何幫助你保證足夠的記憶力,以便付出麻煩。
你是否真的向自己證明這是一個問題呢?在使用字符串時,我很少發現需要擔心內存 - 尤其是如此小的內存。如果它沒有出現問題,那麼不要擔心它,直到它。如果字符串引起你的內存問題,這是一個簡單的修復。否則使用一個字符串,甚至不考慮內存問題。 –
我有一個非常強烈的邏輯,它將數千個這樣的內容存儲在內存中,所以每一個都有幫助。 –
@William如果性能很關鍵,爲什麼不聲明'enum LanguageCode:short'並保存2個字節? –