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
“由于String是不可以变对象,所以所以优化后为“xxxyyZZ”在内存中都只有一份。”
就是说常量“xxxyyZZ”与变量name共用一份内存是吧。
还有,
1、windbg这个是什么工具,能看到对象在内存中的结构?
2、楼上所指标识字符编码的前缀是存在的吗,或者他说的是其它语言的情况
3、.Net中到底什么编码格式,有什么方式或文档能证明吗?
4、你最后算式中第一步的11我不清楚是怎么算出来的,麻烦讲解一下。
谢谢你的解答,静候你的指教
@小白程序猿:
指教谈不上~
是的,所有内容为"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: 引楼上的回答“同时,.NET中的字符串都有一个前缀标识,通过前缀标识可以识别字符串数据的编码格式,这个前缀占用3字节。”我的第2问是指这个。
还有第4个,xxxyyzz 这个只有7个字母啊??
@小白程序猿:
通过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: 虽然最后的位数计算不太明白,特别是这个8 offset(m_firstChar)不太好理解 ,不过总体思路和方向解决了我的疑问,最后答案就是你了
.net中,每个字符串都是独立的分配内存空间,并且在.NET的封装下,string类型是一个介于值类型与指针类型之间的数据对象类型。
当对变量重新赋值等操作后,都是分配新的独立内存块,而不是在原有的基础上进行扩充。
字符串在.NET中都是以UTF-8的形式存储,也就是每个字符都占用1或者3个字节:asc值小于128的用一个字节表示,否则都用3字节。
同时,.NET中的字符串都有一个前缀标识,通过前缀标识可以识别字符串数据的编码格式,这个前缀占用3字节。
所以,你的问题的答案是:10字节。
谢谢你的回答。
“当对变量重新赋值等操作后,都是分配新的独立内存块,而不是在原有的基础上进行扩充。”
字符串的赋值应该还和编译常量和运行变量以及初始创建有关吧?能从这个角度解释一下吗?
@小白程序猿: 没关系。
你的语句该占用多少内存,这个是很难估算的。我们通常考虑的是数据占用的内存。一般来说,假如一个软件,因为代码占用内存太多而需要刻意的关注的时候,这个软件都必须用汇编语言来编写,甚至还不能用常规的汇编方式(也就是说改用类似于二进制那种方式来编程了)。.NET的程序编译默认情况下生成的文件大小都是4K为单位。
@笨笨蜗牛: 额,这个其实就是一道面试题,只是为了考察C#中对字符串内存分配的问题。我就只想知道这个方面的答案而已,汇编太底层了,早忘光了
@小白程序猿: 哦。这样说来,这个语句需要定义三个字符串常量,每个常量占用的内存空间大小按照我前面的方法运算,然后运算结果存储于变量中,变量占用的空间也用这个方案计算就好。
不过,我这个答案是否正确我不能确认,我真的还从没有从这个角度考虑过问题(这个问题通常都是在汇编层次或者在C/C++语言之类的底层开发的时候考虑)。
有了结果给我个消息哦。