NSString的引用计数问题

NSString的神奇的引用计数问题。

NSString的retainCount的变化

用NSString声明的字符串变量的retainCount变化由你初始化字符串时的方式决定


__NSCFConstantString(编译时)

用NSString *str = @”123”;定义的字符串是常量字符串
这些对象地址相同,是因为他们都是__NSCFConstantString对象,也就是字符串常量对象,可以看到其isa都是__NSCFConstantString,该对象存储在栈上,创建之后由系统来管理内存释放,相同内容的NSCFConstantString对象地址相同。该对象引用计数很大,为固定值不会变化,表示无限运行的retainCount,对其进行retain或release也不会影响其引用计数。

当创建一个NSCFConstantString对象时,会检测这个字符串内容是否已经存在,如果存在,则直接将地址赋值给变量;不存在的话,则创建新地址,再赋值。

总的来说,对于NSCFConstantString对象,只要字符串内容不变,就不会分配新的内存地址,无论你是赋值、retain、copy。这种优化在大量使用NSString的情况下可以节省内存,提高性能。

__NSCFString(运行时)

使用stringWithFormat创建的NSString为变量,系统会进行引用计数。
在上面的输出结果中,我们看到另外还有两类isa分别是:__NSCFStringNSTaggedPointerString,先来看__NSCFString。

在我的理解,__NSCFString对象是一种NSString子类,存储在堆上,不属于字符串常量对象。该对象创建之后和其他的Obj对象一样引用计数为1,对其执行retain和release将改变其retainCount。

__NSTaggedPointerString

这个对象是标签指针,苹果在 64 位环境下对NSString、NSNumber等对象做了一些优化。简单的说就是把指针指向的内容直接放在了指针变量的内存地址中,在 64 位环境下指针变量的大小达到了 8 位,能容纳长度较小的内容,于是使用了标签指针来优化数据的存储。从其引用计数可以看出,这种对象也是无垠的retainCount,这种对象存储在指针的内容中。

对 NSString对象来说,当非字面量的数字,英文字母字符串的长度小于等于9的时候会自动成为NSTaggedPointerString类型,如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为__NSCFString类型。


  1. stringWithString取决于后面跟的string, 后面string的retainCount是多少那么用stringWithString创建的对象就为多少

用NSMutableArray结合着NSMutableString来观察一下retainCount的变化。


操作系统的内存管理分成堆和栈。

在堆中分配的内存,都适用引用计数模式;在栈中则不是。

NSString 定义的对象是保存在栈中,所以它没有引用计数,不是通过引用计数对内存进行管理的。常量的引用计数会是一个很大的整数,测试的结果显示它是-1. 对该对象进行 retain 操作,不好改变它的retainCount 值。

NSMutableNSString 定义的对象,需要先分配堆中的内存空间,再初始化才能使用。它是采用引用计数管理内存的。对该对象做 retainCount 操作则每次增加一个。

其实,引用计数是对内存区域的空间管理方式,是应从内存块的视角去看的。任何对象都是指向内存块的指针,有多少个指针指向这个内存块,这个内存块就有多少个引用计算。

NSString在Objective-C中是一种非常特殊的对象,其引用系数不受引用计数规则的控制。NSString对象不管是alloc、retain还是release,其引用计数都是-1。对于NSString来说,用alloc和用retain都是指向同一块内存,区别不大。对于NSMutableString来说,alloc实际上就是开辟了一块新内存,再把内容复制进来,而retain内存不变引用计数+1。如果NSMutableString中的内容被改变了的话,用retain之后内容也被改变。这是写程序过程中所不想要的结果。所以这种情况下,用 copy比较安全。苹果的官方SDK,都把NSString属性声明为copy,比如UILabel中的两个属性。

参考:

stackoverflow上关于NSCFString和NSConstantstring的区别

NSString特性分析学习

文章目录
  1. 1. NSString的retainCount的变化
    1. 1.1. 用NSString声明的字符串变量的retainCount变化由你初始化字符串时的方式决定
    2. 1.2. __NSCFConstantString(编译时)
    3. 1.3. __NSCFString(运行时)
    4. 1.4. __NSTaggedPointerString
  2. 2. 用NSMutableArray结合着NSMutableString来观察一下retainCount的变化。
本站总访问量 本站访客数人次 ,