PythonのPandasでメモリリーク?リークの可視化と暫定対策

株価データをスクレイピングするスクリプトを書いたら、いつもまにかPCのメモリがMAXになっていた。

そして、Pythonのスクリプトが次のようなエラーを吐いた。

メモリリークしているなぁ・・・・。

 
 

Pythonは必要に応じて自動的にガベージコレクションを行う。

通常の用途では明示的にガベージコレクションを行う必要はない・・・はずだけど?

今回は駄文だ。いつも駄文?やかましい!

根本的に理解してない可能性があるので、賢い方々コメントをください。

そうそう、実は期間限定で日記のコメント欄を解放してるよ。

SPAMや荒らしが多い可能性もあるので、トライアルだ。

メモリリークを見えるようにする

問題解決のフローの最初は現状把握だって習ったよ。

gcモジュールでガベージコレクション

明示的にガベージコレクションを行うにはgcモジュールのcollect関数を呼び出す。

これはPandasに限らず定番だが、使い終わったデータのメモリ領域を解放することが大事。

C言語じゃないし、やってないな・・・。

そして、やってみても変わらないよ?

ガーベージコレクションの過程をデバッグ

ネット上で、メモリリーク(開放不可オブジェクト)を出力するサンプルを見つけた。

具体的には、gc.set_debugをコールして、リークの起きるオブジェクトをリサイクルせず、gc.garbageリストに保持させる。

その後、gc.collectでガーベージコレクションを強制実行した後で、開放不可オブジェクトを出力する。

循環参照とは次のようにモジュールの参照がループしてしまうことを指す。

  • モジュールAがモジュールBを参照
  • モジュールBがモジュールAを参照

上記のスクリプトを動かした時の結果は次のとおり。

そもそも、Python では、コードで使用されていたメモリーが OS に返されるという保証はない。

ガーベージコレクションで保証されるのは、オブジェクトで使用されていたメモリーが収集され、将来のいずれかの時点において別のオブジェクトで使用されるために解放されるということのみ。

試してみる

実際の作成したスクリプトはマルチスレッドを使ったり、CSVファイルを呼び出したり書き込んだりを何度も繰り返している。

どの部分を取り出してもリークしている可能性があるが、とりあえずpandas のread_htmlを呼び出した部分だけ確認してみる。

インストールに必要なライブラリは次のとおり。

lxmlはHTML以外にもXMLに唯一対応しており、標準ライブラリよりも高速で動作する。

html5libはBeautifulSoup4やHTML5などに対応しているが動作が遅い。

 
 

で、コードはこうなる。

Pandasを使うとwebページの表をスクレイピングするのが簡単過ぎ。

でも私が使うとメモリリークしてるけどね。

 

さあ、いよいよ実行。

・・・・これ、Pandaのライブラリを使った先でメモリリークしているじゃん。

ありえない気もするけど、メモリ増加は事実だ。

メモリリーク対策

問題、課題、施策。技術がないと施策が分からない。

教えて、ぐーぐる先生!私を助けて!

dtypeの設定で32bitにする

Pandasにおいては、これが結構効くらしい。

Pandasは自動で型が推定されるが、その際に必ず大きめの型が指定される。

例えば、float型の場合、float32で足りる場合でも、float64にする。

float32とfloat64だと、2倍のメモリ使用量の違いだ。

ただし、32bitで必要な精度が得られるか事前に確認を。

型の自動指定

Kaggleで次のような便利な関数を見かけた。

各列の値をみて、メモリ使用量が最小になるように型を自動で設定してくれる関数だそうだ。

この関数にDataFrameを入れてあげることで、メモリ使用量を削減できる。

関数が処理を実行する時間のオーバーヘッドはあるものの、メモリ利用率に関しては効果が大きい。

read_htmlを使わない

自分でパースする関数を作ってしまう方法だ。

ここに工数を使いたくないので、これは最後の手段。

スクリプトを一度修正させる

Pythonでfor文回すのをやめる。

Pythonで1周動かすのが問題ないなら、ループ処理をバッチファイルで制御する。

例えば、次のようにする。

exec.bat

main.py

この方法をネットで見つけて笑ってしまった。

が、工数を考えると実はこれで十分かもしれない。

で、どうしたか?

バッチファイルで凌ぐことにした。

根本原因は解決してないが、日曜大工だと割り切って次の作業に取り掛かろう。

うーん、気持ち悪いけど、ここに時間を割いてる余裕はない。

さすがにデータ取得に時間をかけてる場合じゃない。

タイトルとURLをコピーしました