35、用“僵尸对象”调试内存管理问题
调式内存管理问题很令人头疼。(因为有些问题不是必现的!!!)
大家都知道,向已回收的对象发送消息是不安全的。这么做有时可以,有时不行。具体可行,完全取决于对象所占内存有没有为其他内容所覆写。而这块内存有没有移做他用,又无法确定。因此,应用程序只是偶尔崩溃。在没用崩溃的情况下,那块内存可能只复用了其中一部分,所以对象中的某些二进制数据依然有效。
还有一种可能,就是那块内存恰好为另外一个有效且存活的对象所占据。这种情况下,运行期系统会吧消息发到新对象那里,而此对象也许能应答,也许不能。如果能,那么程序就不崩溃,可你会觉得奇怪:为什么收到消息的对象不是预想的那个呢?若新对象无法响应选择子,则程序依然会崩溃。
所幸Cocoa提供了“僵尸对象”(Zombie Object)模式:运行期系统会把所有已经回收的实例转化成特殊的“僵尸对象”,而不会真正回收它们。这种对象所在的核心内存无法重用,因此不可能遭到覆写。僵尸对象收到消息后,会抛出异常,并给出描述。
开启方式:Scheme -> Run -> Diagnostics -> Enable Zombie Objects (勾选)
runtime发现如果开启该模式,则NSObject的dealloc方法会被“调配”(swizzle),从而执行将对象的类改为指向_NSZombie_OriginalClass类。_NSZombie_类并未实现任何方法,没有超类,跟NSObject一样是个“根类”,该类只有一个实例变量isa,所有OC的根类都必须有此变量。由于这个轻量级的类没有实现任何方法,所以发给它的消息需要寄过“完整的消息转发机制”(full forwarding mechanism)。
要点:
系统在回收对象时,可以不将其真的回收,而是将其转化为僵尸对象。通过环境变量
NSZombieEnabled可开启此功能系统会修改对象的
isa指针,令其指向特说的僵尸类,从而使该对象变为僵尸对象。僵尸类能够响应所有的选择子,响应方式为:打印一条包含消息内容及其接受者的消息,然后终止应用程序
Last updated
Was this helpful?