首页 新闻 会员 周边

C#中字符串内存分配问题

0
[已解决问题] 解决于 2012-04-25 17:16

在C#:

string name = "xxx"+"yy"+"ZZ";

该句占用多少内存或需分配多少空间?

小白程序猿的主页 小白程序猿 | 菜鸟二级 | 园豆:202
提问于:2012-04-25 13:11
< >
分享
最佳答案
0

string name = "xxx"+"yy"+"ZZ";  会被编译器优化为 string name = "xxxyyZZ";

由于String是不可以变对象,所以所以优化后为“xxxyyZZ”在内存中都只有一份。

 

我们可以用windbg看到String的具体大小:

----------------------------------------------------------

Name: System.String
MethodTable: 5b4bf9e8
EEClass: 5b1f8bb0
Size: 28(0x1c) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: xxxyyZZ
Fields:
MT Field Offset Type VT Attr Value Name
5b4c29b4 4000103 4 System.Int32 1 instance 7 m_stringLength
5b4c1e04 4000104 8 System.Char 1 instance 78 m_firstChar
5b4bf9e8 4000105 8 System.String 0 shared static Empty

----------------------------------------------------------

也就是说“xxxyyZZ”在内存中占28 bytes.

这28 bytes是这样分配的:

.net 在内部使用UTF-16来编码的,也就是说像"xxxyyZZ"这种常见的字母用16 bits = 2 bytes来编码。

“xxxyyZZ”,其后面有个看不见的结束符"\0",所以他占用:

11 * 2 bytes = 22 bytes

22 + 4 bytes(Int32类型的m_stringLength) = 26 bytes

26 + 2 bytes(Char类型的m_firstChar) = 28 bytes

奖励园豆:5
Jerry Chou | 老鸟四级 |园豆:2642 | 2012-04-25 16:09

由于String是不可以变对象,所以所以优化后为“xxxyyZZ”在内存中都只有一份。

就是说常量“xxxyyZZ”与变量name共用一份内存是吧。

还有,

1、windbg这个是什么工具,能看到对象在内存中的结构?

2、楼上所指标识字符编码的前缀是存在的吗,或者他说的是其它语言的情况

3、.Net中到底什么编码格式,有什么方式或文档能证明吗?

4、你最后算式中第一步的11我不清楚是怎么算出来的,麻烦讲解一下。

谢谢你的解答,静候你的指教

 

小白程序猿 | 园豆:202 (菜鸟二级) | 2012-04-25 16:41

@小白程序猿: 

指教谈不上~

是的,所有内容为"xxxyyZZ"的变量都引用这块内存。

1,windbg是WIndow的下的调试工具。http://en.wikipedia.org/wiki/WinDbg 安装了sos.dll 扩展就可以看.net的对象结构。

2,没明白你的意思。

3,MSDN http://msdn.microsoft.com/en-us/library/system.string.aspx 打开后搜索 UTF-16

4,xxxyyzz不是10个字母嘛,在加个用来确定字符串结束的结束符(\0)。共11个。

Jerry Chou | 园豆:2642 (老鸟四级) | 2012-04-25 16:48

@Jerry Chou: 引楼上的回答“同时,.NET中的字符串都有一个前缀标识,通过前缀标识可以识别字符串数据的编码格式,这个前缀占用3字节。”我的第2问是指这个。

还有第4个,xxxyyzz 这个只有7个字母啊??

小白程序猿 | 园豆:202 (菜鸟二级) | 2012-04-25 16:53

@小白程序猿: 

通过windbg和官方文档来看“NET中的字符串都有一个前缀标识”是错的。

额?是的哦“xxyyyZZ”只有7个字母。

我不清楚为什么Char的offset是8,(可能是内存对齐,不确定)。

7个字母 + 结束符 = 8 * 2 bytes = 16 bytes

+ 4 offset(m_stringLength) = 20

+ 8 offset(m_firstChar) = 28

Jerry Chou | 园豆:2642 (老鸟四级) | 2012-04-25 17:03

@Jerry Chou: 虽然最后的位数计算不太明白,特别是这个8 offset(m_firstChar)不太好理解 ,不过总体思路和方向解决了我的疑问,最后答案就是你了

小白程序猿 | 园豆:202 (菜鸟二级) | 2012-04-25 17:16
其他回答(1)
0

.net中,每个字符串都是独立的分配内存空间,并且在.NET的封装下,string类型是一个介于值类型与指针类型之间的数据对象类型。

当对变量重新赋值等操作后,都是分配新的独立内存块,而不是在原有的基础上进行扩充。

字符串在.NET中都是以UTF-8的形式存储,也就是每个字符都占用1或者3个字节:asc值小于128的用一个字节表示,否则都用3字节。

同时,.NET中的字符串都有一个前缀标识,通过前缀标识可以识别字符串数据的编码格式,这个前缀占用3字节。

所以,你的问题的答案是:10字节。

无之无 | 园豆:5095 (大侠五级) | 2012-04-25 13:35

谢谢你的回答。

当对变量重新赋值等操作后,都是分配新的独立内存块,而不是在原有的基础上进行扩充。

字符串的赋值应该还和编译常量和运行变量以及初始创建有关吧?能从这个角度解释一下吗?

支持(0) 反对(0) 小白程序猿 | 园豆:202 (菜鸟二级) | 2012-04-25 14:14

@小白程序猿: 没关系。

你的语句该占用多少内存,这个是很难估算的。我们通常考虑的是数据占用的内存。一般来说,假如一个软件,因为代码占用内存太多而需要刻意的关注的时候,这个软件都必须用汇编语言来编写,甚至还不能用常规的汇编方式(也就是说改用类似于二进制那种方式来编程了)。.NET的程序编译默认情况下生成的文件大小都是4K为单位。

支持(0) 反对(0) 无之无 | 园豆:5095 (大侠五级) | 2012-04-25 14:21

@笨笨蜗牛: 额,这个其实就是一道面试题,只是为了考察C#中对字符串内存分配的问题。我就只想知道这个方面的答案而已,汇编太底层了,早忘光了

支持(0) 反对(0) 小白程序猿 | 园豆:202 (菜鸟二级) | 2012-04-25 14:26

@小白程序猿: 哦。这样说来,这个语句需要定义三个字符串常量,每个常量占用的内存空间大小按照我前面的方法运算,然后运算结果存储于变量中,变量占用的空间也用这个方案计算就好。

不过,我这个答案是否正确我不能确认,我真的还从没有从这个角度考虑过问题(这个问题通常都是在汇编层次或者在C/C++语言之类的底层开发的时候考虑)。

有了结果给我个消息哦。

支持(0) 反对(0) 无之无 | 园豆:5095 (大侠五级) | 2012-04-25 14:28
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册