String和Char类型如何在.NET中存储在内存中?

时间:2012-05-28 09:57:30

标签: c# memory memory-management garbage-collection clr

我需要存储一个语言代码字符串,例如" en",它总是包含2个字符。

将类型定义为" String"是否更好?或" Char"?

private string languageCode;

VS

private char[] languageCode;

还是有另一种更好的选择吗?

这些2如何存储在内存中?分配值时,将为它们分配多少字节或位?

6 个答案:

答案 0 :(得分:9)

如何存储

stringchar[]都存储在堆上 - 因此存储是相同的。在内部,我会假设string只是char[]的封面,其中包含很多的额外代码,以使其对您有用。

此外,如果你有很多重复的字符串,你可以使用Interning来减少这些字符串的内存占用。

更好的选择

我赞成字符串 - 数据类型是什么以及打算如何使用它会立即更加明显。人们也更习惯使用字符串,因此可维护性不会受到影响。您也将从为您完成的所有样板代码中受益匪浅。微软也付出了很多努力来确保string类型不是一种性能损失。

分配大小

我不知道分配了多少,我相信字符串非常有效,因为它们只分配足够的内容来存储Unicode字符 - 因为它们是不可变的,所以这样做是安全的。如果没有在新数组中分配空间,也无法调整数组的大小,所以我再次假设他们只抓取他们需要的内容。

Overhead of a .NET array?

<强>替代

根据您的信息,只有20种语言代码且性能很关键,您可以声明自己的枚举,以减少代表代码所需的大小:

enum LanguageCode : byte
{
    en = 0,
}

对于两个char(在数组中),这只需要1个字节而不是4个字节,但它确实将可用LanguageCode值的范围限制为byte的范围 - 这对于20件物品来说足够大了。

您可以使用sizeof()运算符查看值类型的大小:sizeof(LanguageCode)。枚举只是底层的基础类型,它们默认为int,但正如您在我的代码示例中所看到的,您可以通过“继承”新类型来更改它。

答案 1 :(得分:4)

简答:使用字符串

答案很长:

private string languageCode;

AFAIK字符串存储为长度为前缀的字符数组。在堆上实例化String对象以维护此原始数组。但是String对象不仅仅是一个简单的数组,它支持基本的字符串操作,如比较,连接,子字符串提取,搜索等。

虽然

private char[] languageCode;

将存储为字符数组,即将在堆上创建一个Array对象,然后它将用于管理您的字符。但它仍然有一个内部存储的长度属性,因此与字符串相比,内存没有明显的节省。虽然可能是一个Array比一个String更简单,并且内部变量可能更少,从而提供更低的内存占用量(这需要进行验证)。

但OTOH你失去了对这个char数组执行字符串操作的能力。即使像字符串比较这样的操作现在变得很麻烦。所以长话短说使用字符串!

答案 2 :(得分:1)

  

这些2如何存储在内存中?分配值时,将为它们分配多少字节或位?

.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个字节用于数组的开销,加上4个字节用于CharStruct个数组。

答案 3 :(得分:0)

如果您想准确存储2个字符,并且效率最高,请使用结构:

struct Char2
{
 public char C1, C2;
}

使用此结构通常不会导致新的堆分配。它只会升级现有对象(以最小可能的数量)或消耗非常便宜的堆栈空间。

答案 4 :(得分:0)

字符串确实具有一个指针长度的大小开销,即32位进程的4个字节,64位进程的8个字节。但话说回来,字符串提供了比字符数组更多的回报。

如果您的应用程序使用了很多短字符串,并且您不需要经常使用它们的字符串属性和方法,那么您可以安全地保留几个字节的内存。但是如果你想将它们中的任何一个用作字符串,你首先必须创建一个新的字符串实例。我无法看到这将如何帮助你保证足够的内存值得给它带来麻烦。

答案 5 :(得分:0)

String只是在内部实现了char类型的索引器,我们可以说string等同于char[]类型,并带有许多额外的代码以使其对您有用,因此,就像数组一样,它总是存储在堆上。

在不给数组分配新空间的情况下无法对其进行操作,因此字符串也是一样,因此它是不可变的

字符串实现IEnumerable<char>

值得注意的一点:当您将字符串传递给函数时,除非使用ref

,否则它就是按值传递