ベクトル化とメモリ

R のベクトル化の例で、

a <- 1:10001
b <- a[1:10000] + a[2:10001]

のように書くと for ループを回すよりも速いというのがよく紹介されているが、メモリ効率はどうなのか。内部的に右辺の2つの項に対応する a のコピーを2つ作っているとしたら、一時的とはいえ、メモリをかなり浪費することになる。

こういう場合のメモリ消費をトレースする方法を知らない。address 関数も、式の中では無力だし。試しに compiler パッケージの cmpfun でバイトコードに変換してから disassemble で中身を見てみたが、読み方がよく分からなかった。また、通常の evaluator とバイトコードインタプリタが同じなのかどうかも分からない。

そこで、原始的ではあるが、

a <- 1:500000001
> b <- a[1:500000000] + a[2:500000001]

と、

a <- 1:500000001
b <- 1:500000001
for (i in a) {
  b[i] <- a[i] + a[i+1]
}

を実行して、動作中のメモリ使用を top で目視確認した。
2つ目のコードでは、i に渡す部分に 1:500000000 と書いてしまうとそこでもメモリを食ってしまうので、苦肉の策としてこうした。ループの最後で添字をオーバーしているが、NA になるだけでメモリ使用には影響しないだろう(違ったら教えて)。

R の integer は 32bit 整数なので、ベクトル1つあたり 500000000*4 = 2GB のはずだ。実際、後者では a と b を確保した時点でのメモリ使用量がほぼ4GBで計算にあっている。そして、実行中もメモリ使用量は変わらない。一方、ベクトル版だと計算中に 8GB を超える。

つまり、ベクトル版はループがCのレベルで回るので極めて高速だが、メモリは愚直に浪費されるということが分かった。こういうのが R の好きになれないところである…… といっても、この最適化をインタプリタに実装するのが大変だというのは分かるが。