Как узнать, почему использование функций PIL приводит к ошибке памяти?

Я использую PIL (библиотеку изображений python), чтобы сделать некоторые манипуляции с изображениями, в частности, я сшиваю изображения вместе.

Мой код, кажется, отлично работает для некоторых изображений в небольших количествах, но иногда я и получаю MemoryError.

Часть, которая особенно странна для меня, заключается в том, что я не делаю манипуляции с битовыми изображениями, все это работает с < 10 изображениями под 10kb.

Я делаю много звонков на Image.resize, но я удивлен, что из этого есть существенные проблемы.

Вот трек стека:

Traceback (most recent call last):                                                                                                                                               
  File "test.py", line 15, in <module>                                                                                                                                           
    pprint(scale_matrix_down((90,90), [inpt]))                                                                                                                                   
  File "/Users/jeremykarmel/Desktop/Python/merger.py", line 105, in scale_matrix_down                                                                                            
    return [shrinkRow(row, row_width_overflow(row)) for row in matrix]                                                                                                           
  File "/Users/jeremykarmel/Desktop/Python/merger.py", line 103, in shrinkRow                                                                                                    
    rest         = [shrinkIm(im, pixels_per_im) for im in row[remaining_pixels:]]                                                                                                
  File "/Users/jeremykarmel/Desktop/Python/merger.py", line 110, in shrinkIm                                                                                                     
    return im.resize((im.size[0] - num_pix, im.size[1] - num_pix))                                                                                                               
  File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1302, in resize                                                                                                    
    im = self.im.resize(size, resample)                                                                                                                                          
MemoryError

Помните, что все изображения меньше 90x90 пикселей.

Я очень в тупике и действительно не уверен, как действовать дальше. Что я могу сделать, чтобы освободить память? Должен ли я звонить оператору del или есть что-то более простое, что я могу сделать? Заранее благодарим за помощь!

Ответ 1

Оказывается, это не ошибка памяти. Как указывал Уинстон Эверт, я фактически подавал отрицательные параметры в метод изменения размера изображения.

Несмотря на то, что в документации на python говорится, что ошибки памяти возникают из-за проблем с памятью, эта ошибка возникает, когда вы даете отрицательные параметры для изменения размера. Мое подозрение состоит в том, что, поскольку PIL сильно использует библиотеки C, это может привести к утечкам с недопустимым вводом, и поскольку библиотека не выполняет проверку границ, ошибка просто пузырится.

Ответ 2

Чтобы объяснить, что на самом деле происходит:

  • Вы пытаетесь изменить размер изображения на отрицательную ширину
  • PIL пытается выделить изображение с отрицательным размером, чтобы оно соответствовало размеру изображения
  • PIL вызывает malloc с отрицательным объемом памяти для хранения изображения с отрицательным размером.
  • malloc принимает значение size_t без знака. В результате, запрос отрицательной памяти интерпретируется как очень большое число, а не отрицательное число.
  • malloc не может выделить что-то большое, поэтому он вызывает ошибку.
  • В PIL это выглядит как ошибка из памяти, поэтому он сообщает об этом как таковой

Таким образом, недопустимые входы не вызывают утечек или другого плохого поведения. Они приводят к плохому запросу malloc и сдаются. PIL может проверить отрицательные размеры и, таким образом, создать лучшее сообщение об ошибке. Возможно, они считают, что это не стоит того, потому что оно уже выдает сообщение об ошибке, если вы это сделаете.

Как бы то ни было, на самом деле исчерпывающая память затруднена, потому что ОС будет довольно сложно поддерживать процесс, например, используя виртуальную память. Ваша система будет болеть до того, как она доберется до точки исчерпания памяти. Поэтому я обнаружил, что большинство ошибок из-за нехватки памяти вызваны запросами на отрицательные объемы памяти. Насколько я помню, единственные реальные ошибки из памяти, которые я получил, были в Java, вероятно, из-за использования виртуальной машины.