美文网首页
2019-06-26 iOS野指针

2019-06-26 iOS野指针

作者: shannoon | 来源:发表于2019-06-26 14:06 被阅读0次

原文地址: https://ctinusdev.github.io/2017/03/03/WriteWildPointer/

野指针的bug应该算是最难查的bug之一了,因为其随机性强,且难以定位,下面就终结了几类常见的高概率野指针写法。

1、对象释放后,指针没有置空。

常见写法1:

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 396px;">

@property (nonatomic, unsafe_unretained) id obj;

</pre>

|

问题原因:
unsafe_unretained申明的obj并不会在对象释放时将指针置空,如果对象释放之后,继续使用obj就有可能出现野指针的问题。
解决方案:
尽量使用weak|strong|copy等来代替unsafe_unretained来修饰属性。如果一定要使用unsafe_unretained,记得对象释放后,将指针置空。

常见写法2:

objc_setAssociatedObject方法中该用OBJC_ASSOCIATION_RETAIN_NONATOMIC修饰的对象误用成OBJC_ASSOCIATION_ASSIGN
问题原因:
这个问题和上面的常见写法1问题是类似的,就不重复了。

常见写法3:

NSNotification/KVO 只addObserver并没有removeObserver

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 1054px;">

@interface viewController: UIViewController

@property (nonatomic, strong) id obj;

@end

@implementation viewController

-(void)someButtonClick:(id)sender

{

[self.obj addObserver:self forKeyPath:@"someKey" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

}

-(void)dealloc

{

//没有移除观察者

}

@end

</pre>

|

问题原因:
self.obj添加了self作为观察者后,是通过unsafe_unretained指针引用的self,如果对象释放之前不移除观察,self.obj对应keyPath发生变化时,仍然会去尝试给self指向的对象发送通知。就可能会出现野指针了。
解决方案:
1、原始方法,记得addObserver和removeObserver成对出现。
2、利用KVOController

2、对象提前释放了

常见写法1:

异步方法block回调中,没有强引用self。

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 302px;">

__weak typeof(self) weakself = self;

[obj method:^(id result) {

[weakself someMethod];

}];

-(void)someMethod

{

self.test = ....;

...

}

</pre>

|

问题原因:
ARC下,由于性能原因self既不是strong也不是weak,而是unsafe_unretained的。上面代码block并没有引用强引用self。若是在执行[weakSelf someMethod]时,刚好self被释放了,那么self.test 这句的执行就有可能造成野指针崩溃。
解决方案:
在进入block时,先强引用weakself。

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 427px;">

__weak typeof(self) weakself = self;

[obj method:^(id result) {

    __strong typeof(self) strongself = weakSelf;

    [strongself someMethod];

}];

</pre>

|

常见写法2:

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 498px;">

@interface viewController: UIViewController

@end

@implementation viewController

-(void)someButtonClick:(id)sender

{

[self.navigationController popViewControllerAnimated:NO];

[self someMethod];

}

@end

</pre>

|

问题原因:
由于self在pop之后就会被释放,在pop之后,继续使用self,就可能会导致野指针。
解决方案:
在pop和dismiss之后不要在使用self,关于self的操作都在pop和dismiss之前。

3、对象的多次释放。

常见写法1:

多个线程同时对某个对象赋值

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

13

14

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 678px;">

@interface SomeClass: NSObject

@property (nonatomic, strong) NSArray *array;

@end

@implementation SomeClass

  • (void)viewDidLoad

{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    self.array = @[@"test"];

});

self.array = @[@"test"];

}

@end

</pre>

|

问题原因:
在调用setArray:时,新的值会被retain,旧的值会被release。如果两个线程同时执行了setArray:,那么旧的值就可能会release放两次。

解决方案:
找个问题不难解决,对象赋之前先加锁,再赋值就可以解决这类问题。

常见写法2:

CoreFoundation层对象Toll-Free Bridging到Foundation层中,已经用了__bridge_transfer关键字转移了对象的所有权之后,又对CoreFoundation层对象调用了一次CFRelease

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 474px;">

CFUUIDRef uuid = CFUUIDCreate(NULL);

CFStringRef cfString = CFUUIDCreateString(NULL, uuid);

NSString *string = (__bridge_transfer NSString *)cfString;

CFRelease(cfString);

</pre>

|

问题原因:
使用__bridge_transfer之后,cfString的所有权已经交由ARC处理,这时再次接手动调用release,会导致重复释放的问题。

解决方案:
1、将__bridge_transfer改为__bridge,不转移对象的所有权。
2、去掉CFRelease(cfString)

相关文章

  • iOS监控-野指针定位

    iOS监控-野指针定位 iOS监控-野指针定位

  • 2019-06-26 iOS野指针

    原文地址: https://ctinusdev.github.io/2017/03/03/WriteWildPoi...

  • iOS 野指针

    参考: https://cloud.tencent.com/developer/article/1070505

  • iOS野指针

    最近在调研野指针的定位工具,对野指针有了更深入的理解,写篇文章总结下。 一、那什么是野指针?这是维基百科上的定义:...

  • iOS 通向野指针的必经之路

    iOS监控-野指针定位 FJFZombieSnifferDemo LXDZombieSniffer 通过objc的...

  • 从两道面试题说起

    iOS 中是否存在野指针的情况? 野指针 野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是...

  • iOS空指针和野指针

    一、什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就...

  • iOS 野指针定位:野指针嗅探器

    一. 前言 最近最近被指派去解决一些线上的崩溃问题,经常遇到野指针导致的崩溃。相对于其他的原因引起的崩溃来说,野指...

  • 链接收藏

    iOS面试题 野指针 使用了释放的内存 内存泄漏 内存没有释放

  • iOS版友盟错误`Application received si

    iOS版友盟错误Application received signal SIGSEGV 找出野指针对象定位 友盟相...

网友评论

      本文标题:2019-06-26 iOS野指针

      本文链接:https://www.haomeiwen.com/subject/zalccctx.html