簡體   English   中英

由於內存壓力,從ABAddressBook提取所有圖像時崩潰

[英]Fetching all images from ABAddressBook crashes due to memory pressure

我正在從IOS通訊錄中查詢所有人員,並將其圖像存儲在本地緩存中。 對於小型地址簿,一切都可以正常工作-但是由於內存壓力, 很多條目(> 1000)會使應用程序崩潰

在調查了該問題之后,似乎ABPersonCopyImageData為該圖像分配了內存,並返回了CFDataRef photoData為2的CFDataRef photoData 。釋放數據CFRelease(photoData)保持為1,這表明ABAddressBookRef addressBook保留了一個引用,可能是由於緩存原因。 在整個循環中,內存消耗呈線性增加。

循環之后, CFRelease(addressBook)最終清除了所有引用並釋放了內存。 因此,一種破解方法是定期發布地址簿並創建一個新地址簿(每100個項目左右),但這有一些缺點。

還有另一種方法可以告訴通訊錄釋放對圖像數據的引用嗎?

- (void)testContacts {
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
    CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (CFIndex idx = 0; idx < nPeople; idx++ ) {
        ABRecordRef person = CFArrayGetValueAtIndex( allContacts, idx );

        if (ABPersonHasImageData(person)) {
            CFDataRef photoData = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
            if (photoData) {
                // do something (eg. store data) - does not affect problem

                CFRelease(photoData);
            }
        }
    }

    CFRelease(addressBook);
}

我認為@autoreleasepool確實會像Volker在評論中建議的那樣幫助您的案例。 調用CFRelease實際上並沒有釋放內存,它只是減少了對象的保留計數,就像在ARC之前release一樣。 因此,直到當前運行循環的當前周期結束時,內存使用量一直累積到下一次自動釋放池耗盡為止。

另外,請注意,您可以使用免費橋接將所有權轉移到ARC,並提高效率:

- (void)testContacts {
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
    NSArray *allContacts = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (CFIndex idx = 0; idx < nPeople; idx++ ) {
        @autoreleasepool {
            ABRecordRef person = (__bridge ABRecordRef)allContacts[idx];

            if (ABPersonHasImageData(person)) {
                NSData *photoData = (__bridge_transfer NSData*)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
                if (photoData) {
                    // do something (eg. store data) - does not affect problem
                }
            }
        }
    }

    CFRelease(addressBook);
}

好的,到目前為止,定期發布addressBook似乎是解決問題的唯一方法,請參見下面的代碼。

每100個條目釋放一次會增加大約8%的執行時間開銷 ,但是正如預期的那樣對於1000個電話簿條目,存儲空間幾乎減少了10倍 (即iPhone 4上為35MB和15秒,而4MB對16.2秒)

我希望任何人都可以提出更好的解決方案,然后再使用。

void abImagesV3() {
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
    CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (CFIndex idx = 0; idx < nPeople; idx++ ) {
        ABRecordRef person = CFArrayGetValueAtIndex( allContacts, idx );

        if (ABPersonHasImageData(person)) {
            CFDataRef photoData = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
            if (photoData) {
                // do something (eg. store data) - does not affect problem
                CFRelease(photoData);
            }
        }

        if (idx%100 == 99) {
            CFRelease(addressBook);
            CFRelease(allContacts);
            addressBook = ABAddressBookCreateWithOptions(NULL, nil);
            allContacts = ABAddressBookCopyArrayOfAllPeople(addressBook);
        }
    }

    CFRelease(addressBook);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM