And why should str1
, str2
, str3
都驻留在不同的内存地址?它们都是相同的不可变字符串。
See bbum的评论在这里 https://stackoverflow.com/questions/23726493/why-memory-for-primitive-data-types-is-not-allocated/23726795#comment36478269_23726795:
是的......一个相关利益的实现细节(但无论如何,决不会使答案无效);[[NSString alloc] initWithString:@"Hello world"]
实际上不会在堆上创建字符串。它只会返回编译器在 mach-o 文件中放置的 __NSCFConstantString (或任何名称)。这只是一个有趣的细节,因为它不会改变您对所述字符串的消耗;它应该像任何其他物体一样对待。
强调我的。
这里发生的事情是,当编译器可以在编译时确定什么是不可变的NSString
对象将是,它以不同的方式创建该字符串。正如 bbum 所说,最终这是一个实现细节,您在编写程序时不必担心。
但这的副作用意味着编译器能够使我的程序更具内存效率,因为它能够找到所有这些实例并使我的所有NSString
它知道的指针应该保存相同的不可变值,所有指针都指向相同的单个内存地址。
我们可能可以通过以下方式获得相同的结果:
NSString *str1 = [[NSString alloc] init];
NSString *str2 = [NSString new];
NSString *str3 = [[NSString alloc] initWithString:@""];
NSString *str4 = [NSString stringWithString:@""];
NSString *str5 = @"";
这些实际上都是同一件事。
但是,如果我们创建另一个字符串:
NSString *str6 = [NSString stringWithFormat:@"%@", @""];
如果我们打印,这将(很可能......我上次检查时)最终得到不同的值str6
作为指针。
还有其他方法可以生成不可变的NSString
在编译时没有像这样优化的对象。这里的要点是,如果编译器可以在编译时知道字符串将是什么,它将创建一个__NSCFConstantString
在内存管理之外的后台,它将尽可能指向该单个实例。一旦它进入运行时间,如果您直接将其指向那里,它只会指向其他任何内容(str6 = str1
)。否则,它不会浪费执行时间来尝试确定字符串是否相等。如果一个新的NSString
碰巧相等并且在编译时没有发生,它只会由 ARC 处理。
编译器无法确定str6
是与其他字符串相同的不可变字符串。这只是构建时的暗示,其他人最终都得到了相同的地址。
另一件有趣的事情是你永远不会看到dealloc
呼吁__NSCFConstantString
编译器正在为以您声明它们的方式声明的变量创建。因此,从内存的角度来看,编译器不仅使您的代码更加高效,而且还删除了all与这些字符串保持一致的内存管理代码的一部分。