PIL使用時にメモリリーク発生

762 views
Skip to first unread message

nomiso

unread,
Jan 30, 2013, 10:34:31 AM1/30/13
to google-app-...@googlegroups.com
いつもお世話になっております。
野見山と申します。

python2.7環境で、PILを使用して画像を加工したりしています。

現在、以下のようなコードでメモリリークが発生しており、原因がよく判っていません。

--------------------------------------------------
from cStringIO import StringIO
from PIL import Image

in_file = StringIO( input_data )
img = Image.open( in_file )

out_file = StringIO()
img.save( out_file, 'JPEG', quality=75 )
new_data = out_file.getvalue()

# input_dataは1.5MB程度のJPEGデータです。
--------------------------------------------------

デプロイ後、1回呼び出すとメモリ使用量は75MBぐらいです。
もう一度実行すると78MB。実行するたびに増えていきます。
10回ぐらい連続実行すると、一気に100MB以上になってしまい、
続けて何度か実行すると、最終的に以下のエラーメッセージが出力されインスタンスが落ちてしまいます。
「Exceeded soft private memory limit with 155.742 MB after servicing 1 requests total」
メモリ使用量はコンソールのInstancesで確認しています。

Image.openのところまでだと、メモリリークは起きていません。
StringIOをclose()してみたり、gc.collect()とかもしてみましたが、解決できませんでした。

詳しい環境は以下です。(app.yaml)
---------------------------------
runtime: python27
api_version: 1
threadsafe: true

libraries:
- name: jinja2
 version: "2.6"
- name: webapp2
 version: "2.5.2"
- name: markupsafe
 version: latest
- name: PIL
 version: "1.1.7"
---------------------------------

PIL使っている方で、同じような現象は起きていないでしょうか?
何卒よろしくお願いいたします。

野見山

nomiso

unread,
Jan 31, 2013, 1:47:53 AM1/31/13
to google-app-...@googlegroups.com
続報です。

どうも画像の解像度によって、メモリが異常に使われるようです。

解像度4928px*3264px、ファイルサイズ1MB程度のJPEG画像を読み込み、PILでquality=75で保存しようとした場合、
デプロイ後の初回アクセスで105MBものメモリが使われ、開放されないままでいます。
その後、数回のアクセスでプロセスが落ちます。

ファイルサイズ2MBでも1000px程度だと問題ありませんでした。

以下、再現するコードです。
画像URLはダミーです。

-----
import webapp2 as webapp
import cStringIO
from PIL import Image
from google.appengine.api.urlfetch import fetch

class Cv( webapp.RequestHandler ):
    def get( self ):


        result = fetch( url )
        input_data = result.content

        in_file = cStringIO.StringIO( input_data )
        img = Image.open( in_file )

        out_file = cStringIO.StringIO()
        img.save( out_file, 'JPEG', quality=75 )
        new_data = out_file.getvalue()

        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.out.write( new_data )

url_map = [
    ('/front/test/cv', Cv ),
]

application = webapp.WSGIApplication( url_map )

------

野見山


2013年1月31日木曜日 0時34分31秒 UTC+9 nomiso:
Reply all
Reply to author
Forward
0 new messages