首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS 開發:大文件分塊寫入 ZIP 導致內存洩漏崩潰的解決方案

     編輯:程式設計綜合問答

問題現象

使用 NSFileHandle 分塊讀取 25-30MB 大文件並寫入 ZIP 流時,應用因內存佔用過高被系統強殺(Jetsam)。代碼在循環中持續創建 NSData 對象,且未及時釋放,導致內存峰值過高。

核心原因

  • NSData *buffer = [fileHandle readDataOfLength:chunkSize] 每次創建新對象。
  • 循環內無 @autoreleasepool,臨時對象累積在主釋放池中,直到循環結束才釋放。
  • 大文件分塊數多(如 30MB / 64KB ≈ 480 次),臨時對象佔用大量內存。

解決方案:循環內添加 @autoreleasepool

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:sourcePath];
NSOutputStream *streamBIG = [NSOutputStream outputStreamToMemory]; // 或寫入文件流
[streamBIG open];

const NSUInteger chunkSize = 64 * 1024; // 64KB 分塊
uint64_t offset = 0;
uint64_t fileSize = [self fileSizeAtPath:sourcePath];

NSData *buffer = [fileHandle readDataOfLength:chunkSize];
while ([buffer length] > 0) {
    @autoreleasepool {
        // 關鍵:每次循環創建獨立釋放池,及時釋放 buffer 等臨時對象
        [streamBIG writeData:buffer];
        offset += [buffer length];
        [fileHandle seekToFileOffset:offset];
        buffer = [fileHandle readDataOfLength:chunkSize];
    }
}

[streamBIG close];
[fileHandle closeFile];

進階優化建議

1. 調整分塊大小

// 根據文件大小動態調整,平衡內存與 I/O 次數
NSUInteger chunkSize = fileSize > 100*1024*1024 ? 1024*1024 : 64*1024; // 大文件 1MB,小文件 64KB

2. 使用 dispatch_io 異步 I/O(iOS 5+)

dispatch_io_t readChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, 
    sourcePath, O_RDONLY, 0, queue);
dispatch_io_t writeChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, 
    destPath, O_WRONLY | O_CREAT | O_TRUNC, 0644, queue);

dispatch_io_read(readChannel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error) {
    if (data) {
        dispatch_io_write(writeChannel, 0, data, queue, ^(bool done, dispatch_data_t data, int error) {
            // 寫入完成回調
        });
    }
    if (done) {
        dispatch_io_close(readChannel, 0);
        dispatch_io_close(writeChannel, 0);
    }
});

優勢:系統自動管理內存映射、分頁讀寫、內存壓力釋放,適合超大文件(>100MB)。

3. 使用第三方庫:ZipArchive / SSZipArchive

成熟開源庫已處理內存管理、多線程、進度回調、加密等複雜邏輯,推薦生產環境直接使用。

內存調試技巧

  • Xcode Debug Navigator 觀察內存曲線,確認峰值是否超過 Jetsam 限制(通常 150-300MB 視設備而定)。
  • Instruments -> Allocations / Leaks 定位具體洩漏對象。
  • 設置環境變量 MallocStackLogging=1 獲取分配堆棧。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved