①基础
[toc]
知识架构
目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1、几个本质
>
2、空指针和未初始化的指针
(1)、空指针和未初始化的指针的区别:
(2)、为什么指针变量定义时一定要初始化?
>
3、野指针与悬空指针
(1)、指针与内存的常见使用顺序
(2)、内存泄漏的概念
(3)、野指针概念
(4)、在iOS中野指针的后果
(5)、分析野指针的产生原因及解决办法
>
4、iOS NSerror 用双重指针理解
>
5、指针和引用的区别
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1、堆和栈的区别?
>
2、浅拷贝和深拷贝的区别
>
3、分析NSString、NSMutableString等类的copy、mutableCopy
(1)、分别对NSString、NSMutableString进行copy、mutableCopy生成的类型是什么?
(2)、分别对NSString、NSMutableString进行copy、mutableCopy操作,是否会开辟新地址,即是属于深拷贝还是浅拷贝?
(3)、将NSString、NSMutableString变量赋值给用copy、strong修饰的NSString属性的时候,是否会开辟新地址,即是属于深拷贝还是浅拷贝?
(4)、将NSString、NSMutableString变量赋值给用copy、strong修饰的NSMutableString属性的时候,是否会开辟新地址,即是属于深拷贝还是浅拷贝?
(5)、自己代码实现copy修饰符,应该怎么写????
>
4、NSCoding和NSCopy
(1)、NSCoding的作用
(2)、NSCopy
>
5、@synthesize和@dynamic区别
>
1
2
3
4
5
6
7
8
9
10
11
12
13 1、内存管理
(1)、在ObjC中,对象什么时候会被释放(或者对象占用的内存什么时候会被回收利用)?
(2)、那怎么知道对象已经没有被引用了呢?
(3)、autorelease、autoreleasepool(自动释放池)
(4)、autoreleasepool(自动释放池)
(5)、autoreleasepool里面对象的内存什么时候释放?
(6)、runloop、autorelease pool以及线程之间的关系
(7)、自动释放池怎样创建
(8)、自动释放池使用注意
(9)、自动释放池的应用/什么时候要用@autoreleasepool
>
2、如何监测内存泄漏
>
1
2 自动释放池底层怎么实现?
>
常用数据类型占用内存大小
64位编译器
char :1个字节
char*(即指针变量): 8个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 8个字节
long long: 8个字节
unsigned long: 8个字节
一、指针
1、几个本质
1 | 数据类型: |
2、空指针和未初始化的指针/野指针
(1)、空指针和未初始化的指针的区别:
①空指针可以确保不指向任何对象或函数;
而②未初始化指针则可能指向任何地方,即它所指向的地址就是随机的,也就说此时它是个野指针。(附:如果一个指针的指向对象后来被删除,却未置为空指针nil,则它也是野指针)
所以空指针在概念上不同于未初始化的指针。
对于malloc在其内存分配的时候,如果内存分配成功,返回的一定不是空指针;但是如果malloc内存分配失败,返回的空指针。而不是一个未初始化的指针。
以下是华为笔试题:
1 | 下面有关空指针和未初始化指针,说法错误的是? |
错误答案是D,因malloc内存分配失败,返回的是空指针。详细请查看原文地址
华为笔试:下面有关空指针和未初始化指针,说法错误的是?
(2)、为什么指针变量定义时一定要初始化?
答:因为你首先要理解一点.内存空间不是你分配了才可以使用,只是你分配了之后使用才安全。
为什么要进行对他初始化呢,因为如果你没对它初始化,那么这个指针所指向的地址就是随机的,即此时它是个野指针。这时候如果你引用这个指针并对它做了修改这个指针所指向的内容的操作的话,如果刚好这个指针所指向的内容恰好是另外一个程序的数据的话,那么你原本随意的一个修改,就造成了对另一个程序的数据的修改了,也就会导致另外一个程序可能不能正常运行了。所以使用前一定要进行初始化。
3、野指针与悬空指针
在C/C++等语言中,
悬空指针(Dangling Pointer)指的是:一个指针的指向对象已被删除,那么就成了悬空指针。
野指针是那些未初始化的指针。
有时也把野指针和悬空指针通称悬空指针。
而好像在iOS中是通称为野指针。
以下内容摘自:百度百科:迷途指针
在计算机编程领域中,迷途指针,或称悬空指针、野指针,指的是不指向任何合法的对象的指针。
当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称迷途指针。
若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的迷途指针,则将产生无法预料的后果。因为此时迷途指针所指向的内存现在包含的已经完全是不同的数据。通常来说,若原来的程序继续往迷途指针所指向的内存地址写入数据,这些和原来程序不相关的数据将被损坏,进而导致不可预料的程序错误。
这种类型的程序错误,不容易找到问题的原因,通常会导致存储器区块错误(Linux系统中)和一般保护错误(Windows系统中)。如果操作系统的内存分配器将已经被覆盖的数据区域再分配,就可能会影响系统的稳定性。
某些编程语言允许未初始化的指针的存在,而这类指针即为野指针。野指针所导致的错误和迷途指针非常相似,但野指针的问题更容易被发现。
(1)、指针与内存的常见使用顺序
在堆中申请了一块内存,并用一个指针指向它。
一般我们都会在不用的时候先释放该指针指向的内存,再将该指针置为空指针。
即一般正确的写法如下:
1 | //指针变量和指针所指向的内存变量是两个不同的概念 |
但是
①、如果我们在未来始终没有去手动释放掉我们开辟的内存的话,会导致内存泄漏;
②、如果释放掉了该内存,却忘了同时释放只想该内存的指针,会导致产生悬空指针或者说是迷途指针,或者有人也称是野指针。
③、如果记得释放指针,却忘了释放指针只想的内存(即记得②忘了①),那么由于指针已经消失,而指针指向的东西还在,那么久永远无法控制这块内存,而导致一定内存泄漏了。
(2)、内存泄漏的概念
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
(3)、野指针概念
C语言: 当我们声明1个指针变量,没有为这个指针变量赋初始值.这个指针变量的值是1个垃圾指针 指向1块随机的内存空间。
OC语言: 指针指向的对象已经被回收掉了.这个指针就叫做野指针.
野指针:指向内存被释放的内存或者没有访问权限的内存的指针。
更详细的概念可查看:百度百科——野指针
(4)、在iOS中野指针的后果
野指针的后果:崩溃EXC_BAD_ADDRESS
(5)、分析野指针的产生原因及解决办法
知识点:任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
“野指针”的成因主要有:
1 | 1)指针变量没有被初始化。(即随机只想的这个指针很有可能只想一块没人用的内存,) |
4、iOS NSerror 用双重指针理解
常见代码如下:
1 | NSError *error = nil; |
可见,如果我们不是传指针的指针&error,而是传error,那么if(error)中的error就肯定是nil了。那就没用了。
所以这里传error的指针的原因可简单概括为:
因为我们要得到一个新的error值。所以如果有方法
1 | - (NSError *)getNewErrorForremoveItemAtPathremoveItemAtPath:(NSString *)path error:(NSError **)error { |
那么这边,我们的error,就可以直接传error本身,甚至不传都是可以的。
但是实际是这些方法本身的返回值,已经被定义为判断能否进行某种操作,而不是操作是否成功给占用了,如这边已经被判断能否进行删除文件给占用了,所以如果我们还想知道这个删除文件操作结果的error,那就把error的指针的指针传进去,最后其出来的就是我们想要的。
所以,猜测其内部结构应该是
1 | - (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error { |
以下解释原因摘自:ios中处理错误为什么传递的是&error,而不是error?
因为 需要将error 传入后修改其值,然后再返回来,返回来后还要保证己经修改过了。
&error传入是传的地址引用,传入后处理函数直接访问变量的地址,可以修改其值再返回同一个地址, 调用函数就可以知道值是否有修改,即是否有错。
而error传入是传的值引用,值引用传入到程序栈中后其实是把原来的值复制了一份传过去,处理函数可以修改,但无法将改后的值传出函数体。
5、指针和引用的区别
(1)定义和性质的区别
①指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;
②而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。
简单点说:一个是存地址,一个是变量别名
(2)指针和引用作为函数参数进行传递时的区别
①用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址
②引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。
二、内存
1、堆和栈的区别?
1 | 一、堆栈空间分配区别: |
八、谈谈内存管理、内存泄露、循环引用
ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露。
1、内存管理
(1)、在ObjC中,对象什么时候会被释放(或者对象占用的内存什么时候会被回收利用)?
答案是:当对象没有被任何变量引用(也可以说是没有指针指向该对象)的时候,就会被释放。
(2)、那怎么知道对象已经没有被引用了呢?
ObjC采用引用计数(reference counting)的技术来进行管理:
1 | 1)每个对象都有一个关联的整数,称为引用计数器; |
与之对应的消息发送方法如下:
对象操作 | OC中对应的方法 | 引用计数的变化 |
---|---|---|
当对象被创建时 | alloc/new/copy/mutableCopy等 | +1 |
持有对象 | retain | +1 |
释放对象 | release | -1 |
废弃对象 | dealloc | - |
1 | 1)当对象被创建(通过alloc、new或copy/mutableCopy等方法)时,其引用计数初始值为1; |
1 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
当需要释放强引用指向的对象时,需要保证所有指向对象强引用置为 nil。__strong
修饰符是 id 类型和对象类型默认的所有权修饰符。
__weak
表示弱引用,对应定义 property
时用到的 weak。弱引用不会影响对象的释放,而当对象被释放时,所有指向它的弱引用都会自定被置为 nil,这样可以防止野指针。
2、如何监测内存泄漏
如果内存管理不当,势必会造成内存泄露。那我们如何快速的来找出内存泄露呢?以前我们可能会使用Instruments来监测,但是我们会发现使用Instruments特别繁琐,而且不一定能定位到内存泄露。
所以这里伟大的Facebook工程师们开源了一些自动化工具来解决监测内存泄露问题:FBRetainCycleDetector、FBAllocationTracker、FBMemoryProfiler。详情查看在iOS上自动检测内存泄露
你在开发大型项目时,如何进行内存泄露检测的?
instruments下有个leaks工具,启动此工具后,运行项目,工具里可以显示内存泄露的情况,双击可找到源码位置,可以帮助进行内存泄露的处理。
END
1 |