题
字符串不变性是按语句工作还是按语句中的字符串工作?
例如,我知道以下代码将在堆上分配两个字符串。
string s = "hello ";
s += "world!";
“hello”将保留在堆上,直到垃圾被收集;现在S引用“ Hello World!”在堆上。但是,以下行在堆上分配了多少个字符串...1 或 2?另外,有没有工具/方法来验证结果?
string s = "goodbye " + "cruel world!";
解决方案
编译器具有用于字符串连接,这是特殊处理为什么第二个例子是只有永远的一个强>字符串。而“实习”是指,即使你跑这条线20000次仍然只有1串。
重新测试结果...的最简单的方式(在这种情况下)可能是在反射器寻找:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] string s)
L_0000: ldstr "goodbye cruel world!"
L_0005: stloc.0
L_0006: ldloc.0
L_0007: call void [mscorlib]System.Console::WriteLine(string)
L_000c: ret
}
正如你可以看到(ldstr
),编译器已经做了这个给你。
其他提示
文字串实习这意味着"hello "
确实不的驻留在堆上但在数据段 [见注释] 的编程'的(并且因此没有资格垃圾收集),同样适用于"world"
,作为用于"hello world"
可还实习,如果编译器足够聪明。
"goodbye cruel world"
将因为由编译器字符串文字级联被处理的东西被扣留。
编辑:我不知道有关数据段声明,请参阅的有关详细信息,这个问题。
其实,大概3.常量字符串为“再见”,为“残酷的世界”常量字符串,然后对结果一个新的字符串。
您可以通过查看生成的代码找到肯定。这取决于编译器,(并且,事实上,在语言,这不明摆着),但你可以通过使用-a标志读的G ++输出(我认为,检查手册页),以获取中间代码
不要相信你“知道”的字符串。你可能看通过字符串执行的源代码。例如您的示例:
string s = "goodbye " + "cruel world!";
在的java将分配一个字符串。 Java的一些扮演漂亮可爱的技巧和将很难智取 - !只是不优化,直到您需要
目前然而,据我所知,使用这种:
String s="";
for(int i=0;i<1000;i++)
s+=" ";
以创建1000空间串仍然倾向于是相当低效的
在一个循环中追加是非常糟糕的,但除此之外,它可能是StringBuilder的那样高效。
这里要小心,因为编译器可以使一些非常不同的优化时的字符串值是在编译时已知的。如果您使用的字符串不知道,直到运行时(从一个配置文件,数据库,或用户输入拉),你会看到一些非常不同的IL。
如果你只是打算做一个或两个字符串连接,我不会担心。
不过,如果你有很多串连的,或者你有一个循环,那么你一定要采取预防措施。在Java世界中,这意味着你使用串联字符串的StringBuffer insteads。
如果它不只是在一条线中,两个字符串的连接可以通过使第一串到StringBuffer,做的级联,并返回结果字符串来实现。
你自己创建的StringBuffer看似矫枉过正,但是这到底是怎么回事反正要发生.-
无论如何不要过早地优化,但也不要低估字符串连接的性能有多差。这不是对象创建,而是它引起的 GC 工作。
有一个实验室(ASP.NET Escalation Engineer) 苔丝·费尔南德斯的 博客显示了一个(相当极端,理所当然的)例子 字符串连接如何让服务器崩溃.
如果编译器是“智能”,也只会是一个字符串“再见残酷的世界!”