日曜プログラミング

休日趣味でやってるプログラミング関連記事をダラダラと

大きなファイルを扱うお話

練習がてらちょっとしたツールでも作ってみようかとした場合、大きなファイルを読み込んで
java.lang.OutOfMemoryError 起きて困ったりした事がちょこちょこあるのでどうするのが良いか
改めて調べてみた。

以前 java.lang.OutOfMemoryError が出た時は、読み込みたい中身がどこか分かっていたし 1 回限
りだったんで、エディタで分割したのを Clojure に読み込ませると言う何ともその場凌ぎな方法で
逃げてた。

今後も似たような状況で毎度毎度それをやるのもなあって事で。

Java 実行時オプションでメモリサイズ増やす

ローカル PC の使い捨てツールで*1どっかのサーバ資源借りるとか言うアプリじゃなければこれが一番手軽。

Java5 以降は、デフォルトのヒープメモリサイズは物理メモリの 1/64 らしい。
物理メモリ 2GB だと 32MB になる。

leiningen だと以下のような感じで project.clj に JVM オプション付けておけば OK。

(defproject hoge-proj "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :jvm-opts ["-Xmx512m"] ; ← 最大メモリサイズ 512MB を指定
  :dependencies [[org.clojure/clojure "1.5.1"]])

with-open マクロ + line-seq など lazy-seq を返す処理の注意

以下が参考になった。
http://kurohuku.blogspot.jp/2013/02/clojurelazyseq.html

要約すると、with-open 内でも lazy-seq な処理だとコケると言うお話。
中身を保持しないなら doseq や doall, dorun でも良いとも。

これは自分もやりそうな気がするので注意しておこう。

明示的な close

clojure.java.io/reader とかは結局 Java の BufferdReader オブジェクトを返すので
一旦変数に保持して何かした後必要なくなれば明示的に close する方法。
つまりは他の命令型言語と何も変わらない。

(def rdr (clojure.java.io/reader "hoge.txt"))

(defn main []
  (do
    (some-fn-1 rdr)
    (some-fn-2 rdr)
    (.close rdr)))

強制力は何もないが明示的な逐次処理ってのを示すのに do かましておくのが良い?

*1:そもそも他のスクリプト言語使えばいいんじゃってのはご最もな 話なんですがまあ練習って事で