我对NSString指针有疑问。我想深究这一点,并试图创建一个理论,以便从基于网络检索的多个信息中获得充分的理解。当我说我没有懒惰时,请相信我,我实际上读了很多,但我仍然有不确定性和问题。你能否确认/否认好/坏,我还提出了(?)表示的其他问题和疑问。
我们走了: 如果我考虑这个非常基本的例子:
NSString *sPointer = [[NSString alloc]initWithString:@"This is a pointer"];
[sPointer release];
我的出发点是:编译器为指针类型保留RAM内存,此内存(也有自己的地址)包含存储另一个变量的内存的内存地址(十六进制 - 二进制)(指向的位置) )。实际指针占用大约2个字节:
1)首先是一些一般问题 - 不一定与目标C相关。关于NSString指针的实际问题将在第2点出现。 字符串是一个“字符串”,其中1个字符占用固定数量的内存空间,比方说2个字节。 这自动意味着字符串变量占用的内存大小由字符串的长度定义。 然后我在维基百科上看到这个: “在现代字节可寻址计算机中,每个地址标识一个存储字节;数据太大而无法存储在单个字节中,可能存在于占用一系列连续地址的多个字节中。” 所以在这种情况下,字符串值实际上由多个地址包含,而不是由单个1包含(这已经与我在任何地方读取的不同)(?)。 这些多个地址如何包含在1指针中?指针也会分成多个地址吗? 您知道计算机中的哪个组件实际识别并分配实际地址“代码”吗?
现在我的实际问题;
2)在我的例子中,代码做了两件事:
好的,我的问题;我想知道当你释放指针[sPointer release]时会发生什么?你实际上是在释放指针(包含地址),还是你也从内存中释放了实际的“字符串变量”? 我已经了解到,当您删除引用时,存储实际变量的内存将在编译器需要内存时被覆盖,因此不需要在此时清除它。这是错的吗? 如果它是正确的,为什么他们说出于性能原因释放NSString指针非常重要,如果你只是释放基本上只包含几个字节的指针?或者我错了,实际变量存储的内存实际上也是用“释放”消息一次清除的?
最后还是:原始数据类型没有被释放,但它们“声明”在声明时占用内存空间(但不超过公共指针)。为什么我们不应该发布它们呢?是什么阻止我们做类似的事情:int i = 5,然后是[i release]?
对不起 - 一次有很多问题!在实践中,我从来没有遇到过问题,但理论上,我也真的想要完全理解它 - 我希望我不是唯一的。我们可以讨论这个话题吗? 谢谢你,对不起!
答案 0 :(得分:2)
也许我错了,但我昨天才读到指针通常占用4个字节。这没有回答你的任何问题,但你似乎对此非常感兴趣,所以我想我会提到它。
我认为您混淆的原因是您将原语与Objective-C类混淆。 Objective-C类(或者确切的对象,类的实例)可以接受消息(类似于其他语言中的方法调用)。 retain
就是这样一条消息。这就是Objective-C NSString
对象可以接收retain
消息而不是整数的原语的原因。我认为这是你的另一个困惑。 retain
和release
等不是Objective-C语言结构,它们是您发送给对象的实际消息(思考方法)。这就是为什么它们适用于Objective-C对象而不适用于整数和浮点数等原语。
另一个类似的混淆是,你读到的关于如何存储字符串的内容更多地与C风格的字符串有关,比如char *name = "john"
。但是,当您创建指向NSString
的指针时,它指向NSString
实例,它本身决定如何处理存储实际的字符串字节/字符。这可能与C字符串的存储方式相同或不同。
太大而不能存储在单个字节中的数据可能驻留在占据一系列连续地址的多个字节中。 “所以在这种情况下,字符串值实际上是由多个地址包含而不是单个1(这已经与我在任何地方读取的不同)(?)。这些多个地址如何包含在1指针中?
例如,在C中,指针将指向字符串中第一个字符的地址。
好的,我的问题;我想知道当你释放指针[sPointer release]时会发生什么?你实际上是在释放指针(包含地址),还是你也从内存中释放了实际的“字符串变量”?
您正在向release
实例/对象发送NSString
消息。这一点很重要,以避免进一步混淆。您不是在指针本身上操作,而是根据指针指向的内容,即NSString
对象。所以你不是自己释放指针。在发送对象release
方法之后,如果它的引用计数达到0,那么它将通过释放它存储的所有东西来解除分配它自己,我想这包括实际的字符串。
如果它是正确的,为什么他们说出于性能原因释放NSString指针非常重要,如果你只是释放基本上只包含几个字节的指针?
所以是的,你实际上是将release
消息发送到字符串实例,而它处理如何必须解除分配。如果您只是简单地擦除指针使其不再指向字符串实例,那么您将不再知道在何处/如何访问存储在该位置的数据,但它不会让它神奇地消失,程序不会自动知道它可以使用那个内存。您所暗示的是garbage collection,其中,简单地说,未使用的内存将被自动释放以供后续使用。 Objective-C 2.0确实有垃圾收集,但据我所知它尚未在iOS设备上启用。相反,新版本的iOS将支持称为Automatic Reference Counting的功能,编译器本身负责引用计数。
对不起,如果我没有回答你的所有问题,你问了一下:P如果我的任何信息有误,请告诉我!我试图将答案限制在我认为我知道的地方。
答案 1 :(得分:1)
“或者我错了,实际变量存储的内存实际上也是用”释放“消息一次清除的?”内存不清除,但进入空闲内存池,因此实际上减少了程序的内存打印。如果你没有释放指针,你会继续“占用”内存,直到你消耗掉所有可用的虚拟内存,不仅会破坏你的程序,还会使系统崩溃。
答案 2 :(得分:1)
在我回答这些观点之前,你先从错误的前提开始。指针在非16位系统上占用超过2个字节。在Mac上,32位可执行文件需要4个字节,64个可执行文件需要8个字节。
让我注意以下内容并不完全准确(出于优化和其他一些原因,有几种内部表示形式的字符串,而 initXXX 函数决定实例化哪些), 但是为了使用和理解字符串,解释已经足够了。
NSString是一个类(也是一个相当复杂的类)。一个字符串,即该类的一个实例,包含一些管理ivars和一个另一个指针,它指向一块足够大的分配内存,至少保存构成字符串的字节/代码点。您的代码(准确地说是 alloc 方法)保留足够的内存来包含对象的所有ivars(包括指向缓冲区的指针)并返回指向该内存的指针。这就是你存储在指针中的内容(如果 initWithString:没有改变它 - 但我不会在这里进行,我们假设它没有)。如有必要, initWithString:分配足够大的缓冲区来保存字符串的文本,并将其内存存储在NSString实例内的指针中。所以它是这样的:
sPointer NSString instance buffer
+---------------------------+ +-----------------+ +------+
| addr of NSString instance | ----> | ivar | +-> | char |
+---------------------------+ | ivar | | | char |
| ivar (pointer) | --+ | char |
| ivar | | char |
| etc... | | char |
+-----------------+ | char |
| etc. |
+------+
对于像@"Hello"
这样的硬编码字符串,内部指针只指向已存储在程序中的字符串,在只读内存中。不需要为它分配内存,也不能释放内存。
但是我们假设你有一个分配内容的字符串。 release (手动编码或由自动释放池调用)将减少字符串对象的引用计数(所谓的 retainCount )。如果该计数达到零,则将取消分配 NSString 类的实例,并且在字符串的 dealloc 方法中,将释放包含字符串文本的缓冲区。该内存不会以任何方式清除,它只被内存管理器标记为空闲,这意味着它可以再次用于其他目的。
答案 3 :(得分:1)
答案 4 :(得分:1)
为了论坛,我将简要简要总结一下你的答案。感谢大家对此进行了详尽的澄清,雾气消失了!如果您想添加或纠正某些内容,请不要犹豫:
纠正:Mac上的指针占用4个字节的内存空间而不是2.
指针* sPointer指向NSString类的实例,而不是直接指向保存字符的内存。 NSString实例由一组iVar组成,其中有一个指针iVar指向分配的内存,其中存储构成字符串的char变量(使用initWithString:instance方法时定义)。
[sPointer release];释放消息不会发送到指针本身,而是发送到NSString对象的实例。您不是在指针本身上操作,而是在指针指向的位置(!)。
发送alloc消息时,NSString实例对象的保留计数增加1.当发送“释放”消息时,并不意味着相关内存实际上已被清空,但它会减少保留计数1.当保留计数达到零时,编译器知道先前分配的内存可再次使用以供重用。
呈现存储器地址的方式由操作系统决定。程序中使用的逻辑内存地址与底层实现实际使用的内存地址(物理内存地址)不同。
LOCAL变量(不一定是原始变量)存储在堆栈内存中(与存储在堆内存中的对象实例不同)。这意味着它们将在函数结束时自动销毁(它们会自动从堆栈中删除)。有关内存构造堆栈和堆的更多信息可以在几个线程中找到,这些线程以自己的方式阐明了使用和差异。例如.. What and where are the stack and heap? / http://ee.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html