OGeek|极客世界-中国程序员成长平台

标题: iOS 应用程序在下载非常大的文件时耗尽内存 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-13 02:24
标题: iOS 应用程序在下载非常大的文件时耗尽内存

我知道我的问题的变体已在此处以一种或另一种形式提出了很多次 - 我已经广泛搜索这些帖子好几天了,我认为我的问题是独一无二的。请允许我描述一下:

我在 iPad 4 上有一个 iOS 应用程序,可以将一个大文件(260MB 到 650MB)下载到磁盘。下载期间的内存使用量与下载的数据量成正比。大约 500MB 时,应用会收到内存不足警告,大约 650MB 时会因内存不足而被终止。

我反复使用 Instruments 来尝试追踪分配的来源 - 我已经多次运行分配、VM 分配、泄漏、内存监视器和事件监视器。随着内存的增加,我也拍了很多照片。 Instruments 从未显示来 self 的应用程序的大量分配!内存保持平坦。泄漏也不会报告任何内容。

相反,我一直依赖于向内核询问内存使用情况的一组函数,我在此处的另一个线程上找到了这些函数:

   vm_size_t usedMemory(void) {
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes
}

vm_size_t freeMemory(void) {
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t pagesize;
    vm_statistics_data_t vm_stat;

    host_page_size(host_port, &pagesize);
    (void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    return vm_stat.free_count * pagesize;
}

void logMemUsage(void) {
    // compute memory usage and log if different by >= 100k
    static long prevMemUsage = 0;
    long curMemUsage = usedMemory();
    long memUsageDiff = curMemUsage - prevMemUsage;

    // if (memUsageDiff > 100000 || memUsageDiff < -100000) {
    prevMemUsage = curMemUsage;
    //NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb", curMemUsage/1000.0f, memUsageDiff///1000.0f, freeMemory()/1000.0f);
    printf("Memory used %7.1f (%+5.0f), free %7.1f kb\n", curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f);

    //}
}

使用它让我终于看到 something 在下载循环中消耗了内存。我正在使用 RequestQueue 以及以下方法进行下载:

- (void)connectionNSURLConnection *)connection didReceiveDataNSData *)data
{
    if (_filePath && _filePath.length)
    {
        if (_fileHandle == nil)
        {
            [[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];
            self.fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:_filePath];
            _bytesWritten = _rangeStart;
        }

        [_fileHandle writeData:data];
        _bytesWritten += [data length];
        NSInteger totalBytes = MAX(0, _responseReceived.expectedContentLength) + _rangeStart;

        if (_downloadProgressHandler)
        {
            _downloadProgressHandler(_userData, _userData2, (float)_bytesWritten / (float)totalBytes, _bytesWritten, totalBytes);
        }
    }
}

即使我注释掉 [_fileHandle writeData:data] 调用,我仍然观察到内存增加!我仔细检查了我正在关闭文件句柄并在完成后将其设置为 nil,但在下载期间内存正在增长。

注意:此项目使用 ARC。

目前我没有东西可以尝试。根本不将数据写入文件仍然会导致内存增长。禁用显示下载进度的 UIStatusBar 没有帮助。我在 Instruments 中看不到任何东西。我打算尝试使用 NSOutputStream 来写入文件,但我怀疑这是否会有所帮助,因为根本不写入数据仍然会导致内存增长。

我尝试使用 NSURLCache 并在收到内存不足警告时清除缓存。我尝试将 nil 分配给 didReceiveData 方法中的数据,但这并没有改变任何东西。我还尝试将尽可能多的强指针更改为弱指针,但这只会导致选择器在已释放的实例上被调用。

现在非常欢迎任何建议。



Best Answer-推荐答案


您在 Instruments 中看不到它的事实表明您的 Release 和 Debug 配置之间存在显着差异。您是否在 Instruments 下收到内存警告?

编辑您的方案,选择“配置文件”选项并选择构建配置“调试”。看看这是否与您使用“运行”时看到的相符。如果是这样,那么您可以从那里使用 Instruments 来追踪它。

这是一个远景,但要验证的一件事是您没有意外打开 NSZombies。如果你这样做了,你会看到这种行为。转到您的方案并检查“运行”选项。查看“诊断” Pane 并确保未选择任何内容。

关于iOS 应用程序在下载非常大的文件时耗尽内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16113426/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://sqlite.in/) Powered by Discuz! X3.4