gpt4 book ai didi

ios - 使用 GCD 复制大文件 - Dispatch IO 消耗大量内存

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:00:43 25 4
gpt4 key购买 nike

我正在将大型文件复制操作从 NSStream 转换为使用 GCD 的调度 IO 实现。

当将两个 1GB 的文件一起复制到一个 2GB 的文件中时,应用程序使用 GCD 会消耗 2GB 的内存。 NSStream 实现仅占用 50MB。

在 Instruments 中,我可以看到 start_wqthread 调用分配了 1MB block ,正如我为调度 IO 高水位线请求的 block 大小,但在写入输出流后没有被释放,他们四处闲逛。

缓冲区写入输出流后如何释放缓冲区?

如果我在 Xcode 中创建一个全新的 OS X Cocoa 应用程序并将以下代码粘贴到 applicationDidFinishLaunching: 方法中,它将消耗 500-2000MB 的内存。 (要进行测试,请将临时文件引用替换为本地文件引用。)

使用面向 OS 10.9 的 OS 10.9 SDK 创建新项目时,ARC 禁止调用 dispatch_release()。在旧项目中以 OS 10.6 为目标时,即使启用了 ARC,也允许调用 dispatch_release(),但不会影响内存占用。

NSArray* files = @[@"/1GBFile.tmp", @"/1GBFile2.tmp"];
NSString* outFile = @"/outFile.tmp";
NSString* queueName = [NSString stringWithFormat:@"%@.IO", [[NSBundle mainBundle].infoDictionary objectForKey:(id)kCFBundleIdentifierKey]];

dispatch_queue_t queue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
dispatch_io_t io_write = dispatch_io_create_with_path(DISPATCH_IO_STREAM, outFile.UTF8String, (O_RDWR | O_CREAT | O_APPEND), (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH), queue, NULL);
dispatch_io_set_high_water(io_write, 1024*1024);

[files enumerateObjectsUsingBlock:^(NSString* file, NSUInteger idx, BOOL *stop) {
dispatch_io_t io_read = dispatch_io_create_with_path(DISPATCH_IO_STREAM, file.UTF8String, O_RDONLY, 0, queue, NULL);
dispatch_io_set_high_water(io_read, 1024*1024);
dispatch_io_read(io_read, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error) {
if (error) {
dispatch_io_close(io_write, 0);
return;
}

if (data) {
size_t bytesRead = dispatch_data_get_size(data);
if (bytesRead > 0) {
dispatch_io_write(io_write, 0, data, queue, ^(bool doneWriting, dispatch_data_t dataToBeWritten, int errorWriting) {
if (errorWriting) {
dispatch_io_close(io_read, DISPATCH_IO_STOP);
}
});
}
}

if (done) {
dispatch_io_close(io_read, 0);
if (files.count == (idx+1)) {
dispatch_io_close(io_write, 0);
}
}
});
}];

最佳答案

我相信我已经使用调度组制定了解决方案。

这段代码本质上是同步地依次复制每个文件(阻塞循环处理下一个文件,直到上一个文件被完全读取和写入),但允许文件读写操作异步排队。

我认为内存过度消耗是由于多个文件的读取同时排队。我原以为这对于串行队列来说会很好,但它似乎阻止了调度组的进展,所以只有读取和写入单个文件的工作才会排队,就可以了。使用以下代码,峰值内存使用量约为 7MB。

现在,单个输入文件排队等待读取,每个读取操作将其相应的写入操作排队,并且输入文件上的循环被阻塞,直到所有读取和写入操作完成。

NSArray* files = @[@"/1GBFile.tmp", @"/1GBFile2.tmp"];
NSString* outFile = @"/outFile.tmp";
NSString* queueName = [NSString stringWithFormat:@"%@.IO", [[NSBundle mainBundle].infoDictionary objectForKey:(id)kCFBundleIdentifierKey]];

dispatch_queue_t queue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
dispatch_group_t group = dispatch_group_create();
dispatch_io_t io_write = dispatch_io_create_with_path(DISPATCH_IO_STREAM, outFile.UTF8String, (O_RDWR | O_CREAT | O_APPEND), (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH), queue, NULL);
dispatch_io_set_high_water(io_write, 1024*1024);

[files enumerateObjectsUsingBlock:^(NSString* file, NSUInteger idx, BOOL *stop) {
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
if (*stop) {
return;
}
dispatch_group_enter(group);
dispatch_io_t io_read = dispatch_io_create_with_path(DISPATCH_IO_STREAM, file.UTF8String, O_RDONLY, 0, queue, NULL);
dispatch_io_set_high_water(io_read, 1024*1024);
dispatch_io_read(io_read, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error) {
if (error || *stop) {
dispatch_io_close(io_write, 0);
*stop = YES;
return;
}

if (data) {
size_t bytesRead = dispatch_data_get_size(data);
if (bytesRead > 0) {
dispatch_group_enter(group);
dispatch_io_write(io_write, 0, data, queue, ^(bool doneWriting, dispatch_data_t dataToBeWritten, int errorWriting) {
if (errorWriting || *stop) {
dispatch_io_close(io_read, DISPATCH_IO_STOP);
*stop = YES;
dispatch_group_leave(group);
return;
}

if (doneWriting) {
dispatch_group_leave(group);
}
});
}
}

if (done) {
dispatch_io_close(io_read, 0);
if (files.count == (idx+1)) {
dispatch_io_close(io_write, 0);
}
dispatch_group_leave(group);
}
});
}];

关于ios - 使用 GCD 复制大文件 - Dispatch IO 消耗大量内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24113764/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com