2012-03-05 3 views
3

У меня есть следующий метод:Объект освобожден с CFRelease вызывает очевидный крах, но только редко

+ (NSString*) getMD5HashFromFile:(NSString*)filePath { 
    CFStringRef md5hash = FileMD5HashCreateWithPath((CFStringRef)filePath, FileHashDefaultChunkSizeForReadingData); 
    NSString *hashStr = (NSString*)md5hash; 
    CFRelease(md5hash); 
    return hashStr; 
} 

я получал случайные сбои на тренажере, около 1 в 20-30 казней. Тот факт, что это было непротиворечиво, не помогало мне раньше копать.

Теперь, когда я снова вижу код, кажется, что md5hash освобождается перед возвратом, что означает, что возвращаемый объект недействителен. Возвращаемое значение используется в другом методе последовательным образом, который иногда падает, но не всегда. Мой вопрос в том, почему это происходит редко и не всегда.

Означает ли это что-то общее с комбинацией кода Obj-C и C и как работают пулы autorelease?

Примечание: ошибка, по-видимому, исправлена ​​с помощью NSString *hashStr = [NSString stringWithString:(NSString*)md5hash], что имеет для меня полный смысл.

ответ

5

Просто потому, что часть памяти освобождена и освобождена, это не означает, что она немедленно возвращается в ОС. Ваше приложение может удерживать его в течение произвольного периода времени, основываясь на многочисленных факторах и на нескольких уровнях. У ОС есть более важные вещи, которые нужно делать иногда, чем вернуть каждую часть памяти, которую вы отпустили, и можете попросить снова через полсекунды. Доступ к памяти, которую вы назвали free(), но технически принадлежащей, не генерирует сигнал. Вот почему существует MallocScribble. Он перезаписывает память, которую вы производите с помощью мусора (0x55), чтобы это было более очевидно при использовании свободной памяти.

Попробуйте следующее:

char *foo = malloc(100); 
strcpy(foo, "stuff"); 
free(foo); 
printf("%s", foo); 

Большую часть времени, который будет работать хорошо, несмотря на то, совершенно неправильно. Теперь отредактируйте свою схему> Диагностика и Включите Scribble. Повторно запустите, и вы увидите кучу «U» (0x55), указывающую, что вы читаете бессмыслицу. Но он все равно не рухнет.

Возможно, вас заинтересует A look at how malloc works on the Mac Мэтта Галлахера.

+0

Спасибо Роб. Я думаю, что это довольно хорошее объяснение. Собственно, теперь, когда я вижу, что это написано, я не понимаю, что я уже это сделал. Видимо, не очень хорошо :) Еще раз спасибо – dimitrios

+0

Мы все забываем, что мы думаем, что мы должны были помнить: D https://twitter.com/#!/cocoaphony/status/174989186032603136 –

0
+(NSString*) getMD5HashFromFile:(NSString*)filePath { 
    CFStringRef md5hash = FileMD5HashCreateWithPath((CFStringRef)filePath, FileHashDefaultChunkSizeForReadingData); 
    NSString *hashStr = [(NSString*)md5hash copy]; 
    CFRelease(md5hash); 
    return [hashStr autorelease]; 
} 

Обязательно сохраните возвращаемое значение в вызывающем абоненте, если вам нужно держаться за него на какое-то время.

2

CFRelease аргумент не должен быть NULL.

Если CFRelease аргумент является NULL, то это вызовет ошибку во время выполнения и вашего приложения будут врезаться

if(md5hash) 
CFRelease(md5hash);