在循环读取大文件时如何防止 RubyMotion 中的内存泄漏
How to prevent memory leaks in RubyMotion when reading large files in loops
RubyMotion 应该进行自动内存管理:
RubyMotion provides automatic memory management; you do not need to
reclaim unused objects.
但是,当循环读取大文件时,我遇到了巨大的内存泄漏:每秒数百 MB/s,就好像我的读取缓冲区从未被释放过一样。
如果我在每个循环的读取缓冲区上使用 release
,泄漏大部分都会消失。问题是,release
使应用程序在循环结束时崩溃。
def readBigBinaryFile(file)
# PURE RUBY WOULD BE
# source=File.open(file,'r')
source =NSFileHandle.fileHandleForReadingAtPath(file)
buffer_size=4096
offset=0
size=File.size(file)
while ( offset + buffer_size ) <= size
# PURE RUBY WOULD BE
# source.seek(offset)
# abuffer = source.read( buffer_size )
# abuffer=abuffer.to_s
source.seekToFileOffset(offset)
abuffer = source.readDataOfLength(buffer_size)
offset+=buffer_size
@dataPointer ||= Pointer.new(:uchar,4)
abuffer.getBytes(@dataPointer, length: 4)
# memory leaks very rapidly in GBs if we don't release the buffer…
# but this relase action will make the application crash once the doSomething lookp is finished
abuffer.release
end
source.closeFile
return false
end
循环是:
x=0
while x < 10000
my_scan_binary_instance=Scan_binary.new() result=my_scan_binary_instance.readBigBinaryFile(NSBundle.mainBundle.pathForResource("sample1MBfile", ofType:"img"))
puts result.to_s
x+=1
end
puts "if we have used 'abuffer.release', we are going to crash now"
我测试了纯Ruby实现,完全没有内存泄漏,也不需要释放调用。
我发现“How do I prevent memory leak when I load large pickle files in a for loop?”关于 Python 循环中的内存泄漏,但是接受的解决方案在 while block
的开头执行 abuffer=nil
readBigBinaryFile
没用。
这是 RubyMotion 的自动内存管理中的错误,还是预料之中的?
最重要的是,如何在不增加 RubyMotion 应用程序的内存使用量的情况下循环读取大文件?
我创建了 a gist with the working pure Ruby implementation, and a repo 重现崩溃的示例应用程序。
我不知道这是否能解决问题,但也许可以尝试更换
abuffer = source.readDataOfLength(buffer_size)
和
abuffer = WeakRef.new(source.readDataOfLength(buffer_size))
有关 WeakRef
的信息,请参阅“4.1. Weak References”。
进行此更改意味着您还将删除对 abuffer.release
.
的调用
尝试将循环体包裹在 autorelease_pool do ... end
中。这应该导致
每个循环要释放的自动释放对象。在循环结束时将 nil
分配给 abuffer
将允许释放缓冲区内存,因为将不再有对它的引用。
while ( offset + buffer_size ) <= size
autorelease_pool do
source.seekToFileOffset(offset)
abuffer = source.readDataOfLength(buffer_size)
offset+=buffer_size
@dataPointer ||= Pointer.new(:uchar,4)
abuffer.getBytes(@dataPointer, length: 4)
abuffer = nil
end
end
RubyMotion 应该进行自动内存管理:
RubyMotion provides automatic memory management; you do not need to reclaim unused objects.
但是,当循环读取大文件时,我遇到了巨大的内存泄漏:每秒数百 MB/s,就好像我的读取缓冲区从未被释放过一样。
如果我在每个循环的读取缓冲区上使用 release
,泄漏大部分都会消失。问题是,release
使应用程序在循环结束时崩溃。
def readBigBinaryFile(file)
# PURE RUBY WOULD BE
# source=File.open(file,'r')
source =NSFileHandle.fileHandleForReadingAtPath(file)
buffer_size=4096
offset=0
size=File.size(file)
while ( offset + buffer_size ) <= size
# PURE RUBY WOULD BE
# source.seek(offset)
# abuffer = source.read( buffer_size )
# abuffer=abuffer.to_s
source.seekToFileOffset(offset)
abuffer = source.readDataOfLength(buffer_size)
offset+=buffer_size
@dataPointer ||= Pointer.new(:uchar,4)
abuffer.getBytes(@dataPointer, length: 4)
# memory leaks very rapidly in GBs if we don't release the buffer…
# but this relase action will make the application crash once the doSomething lookp is finished
abuffer.release
end
source.closeFile
return false
end
循环是:
x=0
while x < 10000
my_scan_binary_instance=Scan_binary.new() result=my_scan_binary_instance.readBigBinaryFile(NSBundle.mainBundle.pathForResource("sample1MBfile", ofType:"img"))
puts result.to_s
x+=1
end
puts "if we have used 'abuffer.release', we are going to crash now"
我测试了纯Ruby实现,完全没有内存泄漏,也不需要释放调用。
我发现“How do I prevent memory leak when I load large pickle files in a for loop?”关于 Python 循环中的内存泄漏,但是接受的解决方案在 while block
的开头执行 abuffer=nil
readBigBinaryFile
没用。
这是 RubyMotion 的自动内存管理中的错误,还是预料之中的? 最重要的是,如何在不增加 RubyMotion 应用程序的内存使用量的情况下循环读取大文件?
我创建了 a gist with the working pure Ruby implementation, and a repo 重现崩溃的示例应用程序。
我不知道这是否能解决问题,但也许可以尝试更换
abuffer = source.readDataOfLength(buffer_size)
和
abuffer = WeakRef.new(source.readDataOfLength(buffer_size))
有关 WeakRef
的信息,请参阅“4.1. Weak References”。
进行此更改意味着您还将删除对 abuffer.release
.
尝试将循环体包裹在 autorelease_pool do ... end
中。这应该导致
每个循环要释放的自动释放对象。在循环结束时将 nil
分配给 abuffer
将允许释放缓冲区内存,因为将不再有对它的引用。
while ( offset + buffer_size ) <= size
autorelease_pool do
source.seekToFileOffset(offset)
abuffer = source.readDataOfLength(buffer_size)
offset+=buffer_size
@dataPointer ||= Pointer.new(:uchar,4)
abuffer.getBytes(@dataPointer, length: 4)
abuffer = nil
end
end