2

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

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

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

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

   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);

    //}
}

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

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)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方法中的数据,但这并没有改变任何东西。我还尝试将尽可能多的强指针更改为弱指针,但这只会导致在释放实例上调用选择器。

在这一点上,任何建议都非常受欢迎。

4

1 回答 1

4

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

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

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

于 2013-04-19T21:11:35.177 回答