2016-05-09 5 views
0

RubyMotion предполагается сделать автоматическое управление памятью:Как предотвратить утечку памяти в RubyMotion при чтении больших файлов в циклах

RubyMotion обеспечивает автоматическое управление памятью; вам не нужно вернуть неиспользуемые объекты.

, но при чтении больших файлов в цикле я сталкиваюсь с огромными утечками памяти: сотни МБ/с в секунду, точно так же, как если бы мой буфер чтения не был выпущен.

Утечки в основном уходят, если я использую 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, но принято решение делать abuffer=nil в начале while block в readBigBinaryFile не работает.

Это ошибка в автоматическом управлении памятью RubyMotion, или это ожидается? И самое главное, как я могу читать большие файлы в циклах без увеличения использования памяти моего приложения RubyMotion?

Я создал a gist с эффективной реализацией Ruby и a repo примера приложения, воспроизводящего сбой.

+0

Я бы рекомендовал прочитать «[ask]», и особенно ссылку на http://catb.org/esr/faqs/smart-questions.html. «[mcve]» указывает, что ваше примерное приложение должно быть в вопросе _itself_. Ссылки на другие сайты подвержены гниению, а затем ломаются, что делает вопрос бесполезным для других в будущем. –

+0

Внешние ссылки - это товар, сам вопрос, надеюсь, вставляет код, который делает вопрос полным и полезным для других, теперь и позже – MichaelC

ответ

2

Попробуйте обернуть тело петли в 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 
+0

отлично работает! Еще меньше утечки памяти, если я также разместил авторекламу вокруг 'my_scan_binary_instance = Scan_binary.new()'. [Ссылка на документы Apple] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html) – MichaelC

1

Я не знаю, если это будет исправить это точно, но, возможно, попробуйте заменить

abuffer = source.readDataOfLength(buffer_size) 

с

abuffer = WeakRef.new(source.readDataOfLength(buffer_size)) 

Престола "4.1. Weak References" для получения информации о WeakRef.

Выполнение этого изменения означает, что вы также удалите звонок abuffer.release.

+0

хорошая идея! Но он не работает. Поэтому я попытался помещать WeakRefs везде, где мог, и «.weak!» В цикле while в doSomething ... безрезультатно! Я также читаю https: //spin.atomicobject.com/2013/12/09/cyclical-references-rubymotion/ – MichaelC

+0

Добро пожаловать в SO. Используйте более эффективный текст привязки для ссылок и не используйте «Редактировать» или «Обновить». Вопросы и ответы имеют историю изменений, поэтому при необходимости мы можем увидеть изменения; Добавьте изменения, как если бы вы их написали первоначально. Улучшенный текст привязки помогает сохранять содержимое доступным для чтения. Также очень полезно суммировать информацию по этой ссылке в вашем ответе, поэтому, если ссылка умирает, полезная информация по-прежнему доступна для будущих поисковиков. –

+1

@MichaelC Мое лучшее предложение тогда было бы задать на [форумах RubyMotion] (http://community.rubymotion.com/), где вы, вероятно, получите лучшую видимость для своего вопроса. –

 Смежные вопросы

  • Нет связанных вопросов^_^