
僵尸对象:一个已经被释放却没有被销毁的对象
其内存已经被系统回收,是不稳定对象,不可以再访问或者使用,因为它的内存是随时可能被别的对象申请而占用的
当使用野指针访问僵尸对象是,可能报EXC_BAD_ACCESS (code=EXC_I386_GPFLT)错误
如何检测僵尸对象:
1、Xcode-开启zombie Objects
不建议默认开启,因为一旦开启,每次通过指针访问对象的时候,都会去检查指针指向的对象是否为僵尸对象。会影响程序的执行效率
2、Xcode的Analyze静态分析
如何避免僵尸对象报错:
将指针的值置为nil
空指针:是指没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
野指针访问僵尸对象示例:
设置成员变量的属性时,默认是 atomic ,提供线程安全的。 添加一些线程锁,防止数据在写入未完成的时候被其他线程读取,造成数据错误,默认使用。
非原子性,线程不安全,在写入的时候其他线程也可以对其进行访问,获取当前的值。优点:提高效率。
对基础数据进行赋值( NSInteger , CGFloat )和C数据类型( int , float , double , char ), BOOL 类型等。存储在栈中,内存不用我们管理。
一般用于修饰 NSObject 和其子类,指向并持有该对象,引用计数会加1。引用计数为0销毁,可以通过将变量强制赋值 nil 来进行销毁。
在赋值是使用传入值的一份拷贝。 copy 关键字和 strong 类似, copy 多用于修饰有可变类型的不可变对象上 NSString , NSArray , NSDictionary 上。 block (用 strong 也可以)等。
__unsafe_unretain 类似于 weak ,但是当对象被释放后,指针依然保存着之前的地址,被释放后的地址变为 僵尸对象,访问被释放的地址就会出问题,所以说他是不安全的。
__unsafe_unretain 在指向的内存地址销毁后,指针本身并不会自动销毁,这也就造成了野指针,之后容易造成 Crash 。 __weak 在指向的内存销毁后,可以将指针变量置为 nil ,这样更加安全。
copy 多用于修饰有可变类型的不可变对象上 NSString , NSArray , NSDictionary 和 block 等,原因:不论是用 strong 还是 copy 修饰的对象,其指针指向的地址依然还是原对象的地址,但一般我们想要一个不可变的,所以用 copy ,而他们的可变类型为什么要用 strong 修饰呢?如果原字符串是 NSMutableString 的时候,使用 strong 只会增加引用计数。但是 copy 会执行一次深拷贝( self 语法会调用 setter 方法,里面会执行一次 copy 方法生成新的对象,指针和对象都不是原来的了),会造成不必要的内存浪费。
不可以,因为对这个数组进行了增删改 *** 作,而copy后的数组变成了不可变数组NSArray,没有响应的增删改方法,所以对其进行增删改 *** 作就会报错。
是属于ios开发中的内存管理问题:在这我简要概述一下,详细讲的话内容挺多,而且是作为一个ios开发人员,或ios开发爱好者,这是必须了解的:
Objective-c中提供了两种内存管理机制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分别提供对内存的手动和自动管理,来满足不同的需求。其实arc 内部机制原理也是来源于mrc ,arc 是在 iOS 5/ Mac OS X 107 开始导入,利用 Xcode42 可以使用该机能。arc的首要目的就是让代码简洁化,编程简单化,开发更顺心应手,减少不必要的小问题小疏忽;顾名思义,自动引用计数管理,关于内存的申请,使用和释放过程都交给系统自动实现,我们可也不用关系里面的过程,但是事实上还是mrc的原理,只是是系统帮我们做了管理;
mrc,手动引用计数器管理,是在我们申请到某一块内存,在使用之后,要手动释放,释放机理涉及到计数器问题,如果未释放内存,会造成内存的浪费,俗称内存泄露,甚至引起很多未知的错误结果,这对程序有威胁很大,但是,何时释放,怎么释放,注意哪些问题,很有讲究,这就是mrc的不便之处,也是苹果推出arc的缘由;
mrc的具体机理,计数器是什么,在程序过程中的变化,在达到什么程度会释放内存,怎么 *** 作;建议查阅相关文档;
mrc ,在代码上下形式主要表现为,调用该对象时,要做retain *** 作,使用完成后要release,最后还要重写dealloc方法,对该类的所有对象做释放,所以在mrc的代码会有autorelease,retain,release等词语,
而arc不允许有这些词汇,应为这些 *** 作都由系统自动完成。
引用计数器
1和内存管理相关的方法
1)alloc 引用计数器自动设为1
2)retain 引用计数器+1 返回了经过+1以后的当前实例对象
3)release 引用计数器-1,并不一定是释放
4)retainCount 获取引用计数器的值
5)dealloc 当实例对象被销毁之前,系统自动调用。
一定要调[super dealloc]
和内存管理相关的名词
1)僵尸对象:此对象被销毁,不能再使用,不能给它发送任何消息
2)野指针:指向僵尸对象(不可用的内存)的指针,给野指针发送消息将会产生不可控的后果。
3)空指针:没有指向任何对象的指针,给空指针发消息不会产生任何行为
内存管理原则
1如果你想持有某个对象,就必须负责让做一次retain *** 作,引用计数器+1
2如果你想放弃对某个对象的持有权,就要负责让其做一次release *** 作,引用计数器-1
3谁retain,谁release。
指针其实是一个内存地址,对于一个内存单元来说,单元的地址即为指针
空指针 :是一个指向空地址的指针,空指针是有效指针,值为nil、NULL、Nil或0等,给空指针发送消息不会报错,只是不响应消息而已,应该给野指针及时赋予零值变成有效的空指针,避免内存报错
野指针 :是指向“垃圾”内存(不可用内存)的指针,这样的指针是不安全的,使用可能产生段错误( 段错误 是指访问的内存超出了系统所给这个程序的内存空间)
产生原因:指针创建时未初始化。指针变量刚被创建时不会自动成为NULL指针,它会随机指向一个内存地址。
僵尸对象 :当xcode勾选zombie objects后 ,运行时系统会把所有已经回收的实例转化成特殊的“僵尸对象”,而不会真正回收他们。这种对象所在核心内存无法重用,因此不可能遭到覆写。僵尸对象收到消息后,会抛出异常,其中准确说明发送过来的消息,并描述了回收之前的那个对象。 僵尸对象 是调试内存管理的最佳方式
悬垂指针 :指针指向的内存已经被释放了 但是指针还存在 这就是一个 悬垂指针 或者说 迷途指针
一级指针 :一级指针就是指指针,里面放的就是元素的地址,我们可以通过访问元素的地址来找到该地址里存放的内容,即元素本身
二级指针 :指针变量也是变量,是变量就有地址,二级指针就可以存放指针变量的地址
一级指针直接访问内容
二级指针间接访问内容
一级指针的内存首地址
二级指针指向一级指针地址
在MRC下,二级指针类型定义为属性、成员变量或者参数都是可行的
在ARC下,二级指针类型则不能定义为属性或成员变量,但是可以作为参数传递
关于 多级指针
转发关于 空指针 应用:
nil :指向一个对象的空指针,对objective c id 对象赋空值
Nil :在iOS中,Nil完全等同于nil
Null : nil == Nil == Null 所以它们在object-c中是可以通用的
NULL :指向其他类型(如:基本类型、C类型)的空指针, 用于对非对象指针赋空值
NSNull :在集合对象中,表示空值的对象
nil 在Objective-C中用于id类型的对象
NSString str = nil;
NSURL url = nil;
id object = nil;
Nil 指向一个类的指针为空,在Objective-C中用于Class类型的对象
NULL 指向C类型的指针为空
用于对非对象指针赋空值简单举例:
int intA = NULL;
char charC = NULL;
struct structStr = NULL;
坏内存访问 :尝试访问一个不可用内存就是坏内存访问
1内存中被过度释放的对象,又称僵尸对象,报EXC_BAD_ACCESS错误调式。访问了一个已经被释放的对象。
2手动设置NSZombieEnabled环境变量:Edit scheme—>Test—>diagnostics—>zombie objects。不建议手动设置,因为会导致内存占用的增长,同时会影响Leaks工具的调式,这是因为设置NSZombieEnabled会用僵尸对象来代替已释放对象。
3启动Instruments,选择Zombies进行调试。
一个OC对象引用计数为0被释放后就变成僵尸对象了,僵尸对象的内存已经被系统回收,虽然可能该对象还存在,数据依然在内存中,但僵尸对象已经是不稳定对象了,不可以再访问或者使用,它的内存是随时可能被别的对象申请而占用的;
野指针出现的原因是指针没有赋值,或者指针指向的对象已经被释放掉了,野指针指向一块随机的垃圾内存,向他们发送消息会报EXC_BAD_ACCESS错误导致程序崩溃;
空指针不同于野指针,它是一个没有指向任何东西的指针,空指针是有效指针,值为nil、NULL、Nil或0等,给空指针发送消息不会报错,只是不响应消息而已,应该给野指针及时赋予零值变成有效的空指针,避免内存报错。
对于一个指向对象的变量,它里面存储的是一个地址,一个指向内存中某块区域的地址。
nil:的作用就是将这个变量置为空,不指向任何地址。
release:的作用是将这个变量指向的内存中的对象的引用计数减一,直到引用计数为零时释放这块内存。
所以,如果你只是做了nil *** 作,那么就会引起内存泄露的问题,因为它永远也不会做release *** 作了。
如果你只是做了release *** 作,那么就有可能引起crash,原因就是只是release(我认为这个对象已经被释放)而没有将变量置为空,当你再对这个变量做 *** 作时就会引起问题,因为你在对一个不存在的对象做 *** 作。
所以建议,不再需要一个对象时,除了要做release *** 作以外还要做nil *** 作。
NSString str; 此时str指向当前对象。所以对它的 *** 作要小心,建议:NSString str = nil;
以上就是关于iOS野指针、僵尸对象、空指针全部的内容,包括:iOS野指针、僵尸对象、空指针、1.iOS中常用的属性修饰符有哪些、IOS开发 arc与非Arc代码的区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)