ÕªÒª£º±¾ÎÄΪiOS/OS XÄÚ´æ¹ÜÀíϵÁÐÎÄÕµڶþƪ¡£×÷Õß@Sam_Lau_Dev ÏêϸÆÊÎöÁËÔÚʵ¼Ê¿ª·¢ÖлáÓöµ½ÄÄЩÄÚ´æ¹ÜÀíÎÊÌ⣬ÒÔ¼°ÈçºÎʹÓù¤¾ßÀ´µ÷ÊԺͽâ¾ö¡£
ÉÏһƪ²©¿Í¡¶iOS/OS XÄÚ´æ¹ÜÀí£¨Ò»£©£º»ù±¾¸ÅÄîÓëÔÀí¡·Ö÷Òª½²ÁËiOS/OS XÄÚ´æ¹ÜÀíÖÐÒýÓüÆÊýºÍÄÚ´æ¹ÜÀí¹æÔò£¬ÒÔ¼°ÒýÈëARCеÄÄÚ´æ¹ÜÀí»úÖÆÖ®ºóÈçºÎÑ¡Ôñownership qualifiers(__strong¡¢__weak¡¢__unsafe_unretainedºÍ__autoreleasing)À´¹ÜÀíÄÚ´æ¡£ÕâÆªÎÒÃÇÖ÷Òª¹Ø×¢ÔÚʵ¼Ê¿ª·¢ÖлáÓöµ½ÄÄЩÄÚ´æ¹ÜÀíÎÊÌ⣬ÒÔ¼°ÈçºÎʹÓù¤¾ßÀ´µ÷ÊԺͽâ¾ö¡£

ÔÚÍùÏ¿´Ö®Ç°£¬ÇëÏÂÔØÊµÀýMemoryProblems£¬ÎÒÃǽ«ÒÔÕâ¸ö¹¤³ÌÕ¹¿ªÈçºÎ¼ì²éºÍ½â¾öÄÚ´æÎÊÌâ¡£
Ðü¹ÒÖ¸ÕëÎÊÌâ
Ðü¹ÒÖ¸Õ루Dangling Pointer£©¾ÍÊǵ±Ö¸ÕëÖ¸ÏòµÄ¶ÔÏóÒѾÊÍ·Å»ò»ØÊպ󣬵«Ã»ÓжÔÖ¸Õë×öÈκÎÐ޸ģ¨Ò»°ãÀ´Ëµ£¬½«ËüÖ¸Ïò¿ÕÖ¸Õ룩£¬¶øÊÇÈÔȻָÏòÔÀ´ÒѾ»ØÊյĵØÖ·¡£Èç¹ûÖ¸ÕëÖ¸ÏòµÄ¶ÔÏóÒѾÊÍ·Å£¬µ«ÈÔȻʹÓã¬ÄÇô¾Í»áµ¼Ö³ÌÐòCrash¡£
µ±ÄãÔËÐÐMemoryProblemsºó£¬µã»÷Ðü¹ÒÖ¸ÕëÄǸöÑ¡Ï¾Í»á³öÏÖEXC_BAD_ACCESS±ÀÀ£ÐÅÏ¢£º

ÎÒÃÇ¿´¿´Õâ¸öNameListViewControllerÊÇ×öʲôµÄ£¿Ëü¼Ì³ÐUITableViewController£¬Ö÷ÒªÏÔʾ¶à¸öÃû×ÖµÄÐÅÏ¢¡£ËüµÄʵÏÖÎļþÈçÏ£º
static NSString *const kNameCellIdentifier = @"NameCell"; @interface NameListViewController () #pragma mark - Model @property (strong, nonatomic) NSArray *nameList; #pragma mark - Data source @property (assign, nonatomic) ArrayDataSource *dataSource; @end @implementation NameListViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self.dataSource; } #pragma mark - Lazy initialization - (NSArray *)nameList { if (!_nameList) { _nameList = @[@"Sam", @"Mike", @"John", @"Paul", @"Jason"]; } return _nameList; } - (ArrayDataSource *)dataSource { if (!_dataSource) { _dataSource = [[ArrayDataSource alloc] initWithItems:self.nameList cellIdentifier:kNameCellIdentifier tableViewStyle:UITableViewCellStyleDefault configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) { cell.textLabel.text = item; }]; } return _dataSource; } @end |
ÒªÏëͨ¹ýtableViewÏÔʾÊý¾Ý£¬Ê×ÏÈҪʵÏÖUITableViewDataSourceÕâ¸öÐÒ飬ΪÁËÊÝÉícontrollerºÍ¸´ÓÃdata source£¬ÎÒ½«Ëü·ÖÀëµ½Ò»¸öÀàArrayDataSourceÀ´ÊµÏÖUITableViewDataSourceÕâ¸öÐÒ顣ȻºóÔÚviewDidLoad·½·¨ÀïÃæ½«dataSource¸³Öµ¸øtableView.dataSource¡£
½âÊÍÍêNameListViewControllerµÄÖ°Ôðºó£¬½ÓÏÂÀ´ÎÒÃÇÐèҪ˼¿¼³öÏÖEXC_BAD_ACCESS´íÎóµÄÔÒòºÍλÖÃÐÅÏ¢¡£
Ò»°ãÀ´Ëµ£¬³öÏÖEXC_BAD_ACCESS´íÎóµÄÔÒò¶¼ÊÇÐü¹ÒÖ¸Õëµ¼Öµģ¬µ«¾ßÌåÊÇÄĸöÖ¸ÕëÊÇÐü¹ÒÖ¸Õ뻹²»È·¶¨£¬ÒòΪ¿ØÖÆÌ¨²¢Ã»Óиø³ö¾ßÌåCrashÐÅÏ¢¡£
ÆôÓÃNSZombieEnabled
ÒªÏëµÃµ½¸ü¶àµÄCrashÐÅÏ¢£¬ÄãÐèÒªÆô¶¯NSZombieEnabled¡£¾ßÌå²½ÖèÈçÏ£º
1. Ñ¡ÖÐEdit Scheme£¬²¢µã»÷£º

2. Run -> Diagnostics -> Enable Zombie Objects

ÉèÖÃÍêÖ®ºó£¬ÔÙ´ÎÔËÐк͵ã»÷Ðü¹ÒÖ¸Õ룬ËäÈ»»áÔÙ´ÎCrash£¬µ«Õâ´Î¿ØÖÆÌ¨´òÓ¡ÁËÒÔÏÂÓÐÓÃÐÅÏ¢£º

ÐÅÏ¢message sent to deallocated instance 0x7fe19b081760´óÒâÊÇÏòÒ»¸öÒÑÊͷŶÔÏó·¢ËÍÐÅÏ¢£¬Ò²¾ÍÊÇÒÑÊͷŶÔÏó»¹µ÷ÓÃij¸ö·½·¨¡£ÏÖÔÚÎÒÃÇ´ó¸ÅÖªµÀʲôÔÒòµ¼Ö³ÌÐò»ácrash£¬µ«ÊǾßÌåÄĸö¶ÔÏó±»ÊÍ·Å»¹ÈÔȻʹÓÃÄØ£¿
µã»÷ÉÏÃæºìÉ«¿òµÄContinue program execution°´Å¥¼ÌÐøÔËÐУ¬½ØÍ¼ÈçÏ£º

ÁôÒâÉÏÃæµÄÁ½¸öºìÉ«¿ò£¬ËüÃÇÁ½¸öµØÖ·ÊÇÒ»Ñù£¬¶øÇÒArrayDataSourceÇ°ÃæÓиö_NSZombie_ÐÞÊηû£¬ËµÃ÷dataSource¶ÔÏó±»ÊÍ·Å»¹ÈÔȻʹÓá£
ÔÙ½øÒ»²½¿´dataSourceÉùÃ÷ÊôÐÔµÄÐÞÊηûÊÇassign£º
#pragma mark - Data source @property (assign, nonatomic) ArrayDataSource *dataSource; |
¶øassign¶ÔÓ¦¾ÍÊÇ__unsafe_unretained£¬Ëü¸ú__weakÏàËÆ£¬±»ËüÐÞÊεıäÁ¿¶¼²»³ÖÓжÔÏóµÄËùÓÐȨ£¬µ«µ±±äÁ¿Ö¸ÏòµÄ¶ÔÏóµÄRCΪ0ʱ£¬±äÁ¿²¢²»ÉèÖÃΪnil£¬¶øÊǼÌÐø±£´æ¶ÔÏóµÄµØÖ·¡£
Òò´Ë£¬ÔÚviewDidLoad·½·¨ÖУº
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self.dataSource; /* ÓÉÓÚdataSourceÊDZ»assignÐÞÊΣ¬self.dataSource¸³Öµºó£¬Ëü¶ÔÏóµÄ¶ÔÏó¾ÍÂíÉÏÊÍ·Å£¬ * ¶øself.tableView.dataSourceÒ²²»ÊÇstrong£¬¶øÊÇweak£¬´ËʱÈÔȻʹÓã¬ËùÓлᵼÖ³ÌÐòcrash */ } |
·ÖÎöÍêÔÒòºÍ¶¨Î»´íÎó´úÂëºó£¬ÖÁÓÚÈçºÎÐ޸ģ¬ÎÒÏë´ó¼Ò¶¼ÐÄÖª¶ÇÃ÷ÁË£¬Èç¹û»¹²»ÖªµÀµÄ»°£¬ÁôÑÔ¸øÎÒ¡£
ÄÚ´æÐ¹Â¶ÎÊÌâ
»¹¼ÇµÃÉÏһƪ¡¶iOS/OS XÄÚ´æ¹ÜÀí(Ò»)£º»ù±¾¸ÅÄîÓëÔÀí¡·µÄÒýÓÃÑ»·Àý×ÓÂð£¿Ëü»áµ¼ÖÂÄÚ´æÐ¹Â¶£¬ÉÏ´ÎÖ»ÊÇÎÄ×ÖÃèÊö£¬²»Ôõôֱ¹Û£¬Õâ´ÎÎÒÃdz¢ÊÔʹÓÃInstrumentsÀïÃæµÄ×Ó¹¤¾ßLeaksÀ´¼ì²éÄÚ´æÐ¹Â¶¡£
¾²Ì¬·ÖÎö
Ò»°ãÀ´Ëµ£¬ÔÚ³ÌÐòδÔËÐÐ֮ǰÎÒÃÇ¿ÉÒÔÏÈͨ¹ýClang Static Analyzer£¨¾²Ì¬·ÖÎö£©À´¼ì²é´úÂëÊÇ·ñ´æÔÚbug¡£±ÈÈ磬ÄÚ´æÐ¹Â¶¡¢Îļþ×ÊԴй¶»ò·ÃÎÊ¿ÕÖ¸ÕëµÄÊý¾ÝµÈ¡£ÏÂÃæÓиö¾²Ì¬·ÖÎöµÄÀý×ÓÀ´½²ÊöÈçºÎÆôÓþ²Ì¬·ÖÎöÒÔ¼°¾²Ì¬·ÖÎöÄܹ»²éÕÒÄÄЩbugs¡£
Æô¶¯³ÌÐòºó£¬µã»÷¾²Ì¬·ÖÎö£¬ÂíÉϾͳöÏÖCrash£º

´Ëʱ£¬¼´Ê¹ÆôÓÃNSZombieEnabled£¬¿ØÖÆÌ¨Ò²²»ÄÜ´òÓ¡³ö¸ü¶àÓйØbugµÄÐÅÏ¢£¬¾ßÌåÔÒòÊÇʲô£¬µÈÏ»á½âÊÍ¡£
´ò¿ªStaticAnalysisViewController£¬ÀïÃæÒýÓÃFacebook Infer¹¤¾ßµÄ´úÂëÀý×Ó£¬°üº¬¸öÈËÈÕ³£¿ª·¢Öлá³öÏÖµÄBugs£º
@implementation StaticAnalysisViewController #pragma mark - Lifecycle - (void)viewDidLoad { [super viewDidLoad]; [self memoryLeakBug]; [self resoureLeakBug]; [self parameterNotNullCheckedBlockBug:nil]; [self npeInArrayLiteralBug]; [self prematureNilTerminationArgumentBug]; } #pragma mark - Test methods from facebook infer iOS Hello examples - (void)memoryLeakBug { CGPathRef shadowPath = CGPathCreateWithRect(self.inputView.bounds, NULL); } - (void)resoureLeakBug { FILE *fp; fp=fopen("info.plist", "r"); } -(void) parameterNotNullCheckedBlockBug:(void (^)())callback { callback(); } -(NSArray*) npeInArrayLiteralBug { NSString *str = nil; return @[@"horse", str, @"dolphin"]; } -(NSArray*) prematureNilTerminationArgumentBug { NSString *str = nil; return [NSArray arrayWithObjects: @"horse", str, @"dolphin", nil]; } @end |
ÏÂÃæÎÒÃÇͨ¹ý¾²Ì¬·ÖÎöÀ´¼ì²é´úÂëÊÇ·ñ´æÔÚBugs¡£ÓÐÁ½¸ö·½Ê½£º
- ÊÖ¶¯¾²Ì¬·ÖÎö£ºÃ¿´Î¶¼ÊÇͨ¹ýµã»÷²Ëµ¥À¸µÄProduct -> Analyze»ò¿ì½Ý¼üShift + Command + B£º

- ×Ô¶¯¾²Ì¬·ÖÎö£ºÔÚBuild SettingsÆôÓÃAnalyze During 'Build'£¬Ã¿´Î±àÒëʱ¶¼»á×Ô¶¯¾²Ì¬·ÖÎö£º

¾²Ì¬·ÖÎö½á¹ûÈçÏ£º

ͨ¹ý¾²Ì¬·ÖÎö½á¹û£¬ÎÒÃÇÀ´·ÖÎöÒ»ÏÂΪʲôNSZombieEnabled²»Äܶ¨Î»EXC_BAD_ACCESSµÄ´íÎó´úÂëλÖá£ÓÉÓÚcallback´«Èë½øÀ´µÄÊÇnullÖ¸Õ룬¶øNSZombieEnabledÖ»ÄÜÕë¶Ôij¸öÒѾÊͷŶÔÏóµÄµØÖ·£¬ËùÒÔÆô¶¯NSZombieEnabledÊDz»Äܶ¨Î»µÄ£¬²»¹ý¿ÉÒÔͨ¹ý¾²Ì¬·ÖÎö¿ÉµÃÖª¡£
Æô¶¯Instruments
ÓÐʱʹÓþ²Ì¬·ÖÎöÄܹ»¼ì²é³öһЩÄÚ´æÐ¹Â¶ÎÊÌ⣬µ«ÊÇÓÐʱֻÓÐÔËÐÐʱʹÓÃInstruments²ÅÄܼì²éµ½£¬Æô¶¯Instruments²½ÖèÈçÏ£º
1. µã»÷XcodeµÄ²Ëµ¥À¸µÄProduct -> ProfileÆô¶¯Instruments£º

2. ´Ëʱ£¬³öÏÖInstrumentsµÄ¹¤¾ß¼¯£¬Ñ¡ÖÐLeaks×Ó¹¤¾ßµã»÷£º

3. ´ò¿ªLeaks¹¤¾ßÖ®ºó£¬µã»÷ºìɫԲµã°´Å¥Æô¶¯Leaks¹¤¾ß£¬ÔÚLeaks¹¤¾ßÆô¶¯Í¬Ê±£¬Ä£ÄâÆ÷»òÕæ»úÒ²¸ú×ÅÆô¶¯£º

4. Æô¶¯Leaks¹¤¾ßºó£¬Ëü»áÔÚ³ÌÐòÔËÐÐʱ¼Ç¼ÄÚ´æ·ÖÅäÐÅÏ¢ºÍ¼ì²éÊÇ·ñ·¢ÉúÄÚ´æÐ¹Â¶¡£µ±Äãµã»÷ÒýÓÃÑ»·½øÈ¥ÄǸöÒ³Ãæºó£¬ÔÙ·µ»Øµ½Ö÷Ò³£¬¾Í»á·¢ÉúÄÚ´æÐ¹Â¶£º


Èç¹û·¢ÉúÄÚ´æÐ¹Â¶£¬ÎÒÃÇÔõô¶¨Î»ÄÄÀï·¢ÉúºÍΪʲô»á·¢ÉúÄÚ´æÐ¹Â¶£¿
¶¨Î»ÄÚ´æÐ¹Â¶
½èÖúLeaksÄܺܿ춨λÄÚ´æÐ¹Â¶ÎÊÌ⣬ÔÚÕâ¸öÀý×ÓÖУ¬²½ÖèÈçÏ£º
- Ê×Ïȵã»÷Leak Checksʱ¼äÌõÄǸöºìÉ«²æ

- È»ºóË«»÷ijÐÐÄÚ´æÐ¹Â¶µ÷ÓÃÕ»£¬»áÖ±½ÓÌøµ½ÄÚ´æÐ¹Â¶´úÂëλÖÃ

·ÖÎöÄÚ´æÐ¹Â¶ÔÒò
ÉÏÃæÒѾ¶¨Î»ºÃÄÚ´æÐ¹Â¶´úÂëµÄλÖã¬ÖÁÓÚÔÒòÊÇʲô£¿¿ÉÒԲ鿴ÉÏһƪµÄ¡¶iOS/OS XÄÚ´æ¹ÜÀí(Ò»)£º»ù±¾¸ÅÄîÓëÔÀí¡·µÄÑ»·ÒýÓÃÀý×Ó£¬ÄÇÀïÒѾÓÐÏêϸµÄ½âÊÍ¡£
ÄÑÒÔ¼ì²âBlockÒýÓÃÑ»·
´ó¶àÊýµÄÄÚ´æÎÊÌâ¶¼¿ÉÒÔͨ¹ý¾²Ì¬·ÖÎöºÍInstrument Leak¹¤¾ß¼ì²â³öÀ´£¬µ«ÊÇÓÐÖÖblockÒýÓÃÑ»·ÊÇÄÑÒÔ¼ì²âµÄ£¬¿´ÎÒÃÇÕâ¸öBlockÄÚ´æÐ¹Â¶Àý×Ó£¬¸úÉÏÃæµÄÐü¹ÒÖ¸ÕëÀý×Ӳ¶à£¬Ö»ÊÇÔÚconfigureCellBlockÀïÃæµ÷ÓÃÒ»¸ö·½·¨configureCell¡£
- (ArrayDataSource *)dataSource { if (!_dataSource) { _dataSource = [[ArrayDataSource alloc] initWithItems:self.nameList cellIdentifier:kNameCellIdentifier tableViewStyle:UITableViewCellStyleDefault configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) { cell.textLabel.text = item; [self configureCell]; }]; } return _dataSource; } - (void)configureCell { NSLog(@"Just for test"); } - (void)dealloc { NSLog(@"release BlockLeakViewController"); } |
ÎÒÃÇÊ×ÏÈÓþ²Ì¬·ÖÎöÀ´¿´¿´Äܲ»Äܼì²é³öÄÚ´æÐ¹Â¶£º

½á¹ûÊÇûÓÐÈκÎÄÚ´æÐ¹Â¶µÄÌáʾ£¬ÎÒÃÇÔÙÓÃInstrument Leak¹¤¾ßÔÚÔËÐÐʱ¿´¿´Äܲ»Äܼì²é³ö£º

½á¹û¸úʹÓþ²Ì¬·ÖÎöÒ»Ñù£¬»¹ÊÇûÓÐÈκÎÄÚ´æÐ¹Â¶ÐÅÏ¢µÄÌáʾ¡£
ÄÇôÎÒÃÇÔõô֪µÀÕâ¸öBlockLeakViewController·¢ÉúÁËÄÚ´æÐ¹Â¶ÄØ£¿»¹ÊǸù¾ÝiOS/OS XÄÚ´æ¹ÜÀí»úÖÆµÄÒ»¸ö»ù±¾ÔÀí£ºµ±Ä³¸ö¶ÔÏóµÄÒýÓüÆÊýΪ0ʱ£¬Ëü¾Í»á×Ô¶¯µ÷ÓÃ- (void)dealloc·½·¨¡£
ÔÚÕâ¸öÀý×ÓÖУ¬Èç¹ûBlockLeakViewController±»navigationController pop³öÈ¥ºó£¬Ã»Óе÷ÓÃdealloc·½·¨£¬ËµÃ÷ËüµÄij¸öÊôÐÔ¶ÔÏóÈÔÈ»±»³ÖÓУ¬Î´±»ÊÍ·Å¡£¶øÎÒÔÚdealloc·½·¨´òÓ¡release BlockLeakViewControllerÐÅÏ¢£º
- (void)dealloc { NSLog(@"release BlockLeakViewController"); } |
ÔÚÎÒµã»÷·µ»Ø°´Å¥ºó£¬Æä²¢Ã»ÓдòÓ¡³öÀ´£¬Òò´ËÕâ¸öBlockLeakViewController´æÔÚÄÚ´æÐ¹Â¶ÎÊÌâµÄ¡£ÖÁÓÚÈçºÎ½â¾öblockÄÚ´æÐ¹Â¶Õâ¸öÎÊÌ⣬ºÜ¶à»ù±¾¹¦ÔúʵµÄͬѧ¶¼ÖªµÀÈçºÎ½â¾ö£¬²»¶®µÄ»°£¬×Ô¼º²é×ÊÁϽâ¾ö°É£¡
×ܽá
Ò»°ãÀ´Ëµ£¬ÔÚ´´½¨¹¤³ÌµÄʱºò£¬ÎÒ¶¼»áÔÚBuild SettingsÆôÓÃAnalyze During 'Build'£¬Ã¿´Î±àÒëʱ¶¼»á×Ô¶¯¾²Ì¬·ÖÎö¡£ÕâÑùµÄ»°£¬Ð´ÍêһС¶Î´úÂëÖ®ºó£¬¾ÍÂíÉÏÖªµÀÊÇ·ñ´æÔÚÄÚ´æÐ¹Â¶»òÆäËûbugÎÊÌ⣬²¢ÇÒ¿ÉÒÔÐÞbugs¡£¶øÔÚÔËÐйý³ÌÖУ¬Èç¹û³öÏÖEXC_BAD_ACCESS£¬ÆôÓÃNSZombieEnabled£¬¿´³öÏÖÒì³£ºó£¬¿ØÖÆÌ¨ÄÜ·ñ´òÓ¡³ö¸ü¶àµÄÌáʾÐÅÏ¢¡£Èç¹ûÏëÔÚÔËÐÐʱ²é¿´ÊÇ·ñ´æÔÚÄÚ´æÐ¹Â¶£¬Ê¹ÓÃInstrument Leak¹¤¾ß¡£µ«ÊÇÓÐЩÄÚ´æÐ¹Â¶ÊǺÜÄѼì²é³öÀ´£¬ÓÐʱֻÓÐͨ¹ýÊÖ¶¯¸²¸Çdealloc·½·¨£¬¿´Ëü×îÖÕÓÐûÓе÷Óá£
|