メモリに保持されている大きなリストからデータにアクセスするプロジェクトに取り組んでいます。リストは非常に大量 (数百万行) であるため、メモリの使用量を常に監視しています。私は OS X を使用しているので、これらのリストを作成するときはアクティビティ モニターを開いたままにしています。
リストが使用するメモリの量は、リストの構成方法によって大きく異なることに気付きましたが、その理由がわかりません。
次に、いくつかのコード例を示します。
(OSX 10.8.3 で Python 2.7.4 を使用しています)
以下の最初の関数は、リストを作成し、同じ 3 つの乱数すべてで埋めます。
以下の 2 番目の関数は、リストを作成し、すべての異なる乱数で埋めます。
import random
import sys
def make_table1(size):
list1 = size *[(float(),float(),float())] # initialize the list
line = (random.random(),
random.random(),
random.random())
for count in xrange(0, size): # Now fill it
list1[count] = line
return list1
def make_table2(size):
list1 = size *[(float(),float(),float())] # initialize the list
for count in xrange(0, size): # Now fill it
list1[count] = (random.random(),
random.random(),
random.random())
return list1
(最初に、上記のコードをもっと効率的に記述できたことを認識しています。2 つの例をできるだけ似たものにするために、このように記述しています。)
次に、これらの関数を使用していくつかのリストを作成します。
In [2]: thing1 = make_table1(6000000)
In [3]: sys.getsizeof(thing1)
Out[3]: 48000072
この時点で、私のメモリ使用量は約 46 MB ジャンプしました。これは、上記の情報から予想されることです。
次の関数に進みます。
In [4]: thing2 = make_table2(6000000)
In [5]: sys.getsizeof(thing2)
Out[5]: 48000072
ご覧のとおり、2 つのリストが使用するメモリは同じです。それらはまったく同じ長さなので、それは予想されることです. 私が予期していなかったのは、Activity Monitor によって与えられたメモリ使用量が 1 GB を超えたことです!
多少のオーバーヘッドがあることは理解していますが、20倍ですか?46MBのリストで1GB?
真剣に?
さて、診断に進みます...
私が最初に試みたのは、ガベージを収集することです。
In [5]: import gc
In [6]: gc.collect()
Out[6]: 0
使用されるメモリ量に違いはありませんでした。
次に、guppy を使用してメモリの移動先を確認しました。
In [7]: from guppy import hpy
In [8]: hpy().heap()
Out[8]:
Partition of a set of 24217689 objects. Total size = 1039012560 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 6054789 25 484821768 47 484821768 47 tuple
1 18008261 74 432198264 42 917020032 88 float
2 2267 0 96847576 9 1013867608 98 list
3 99032 0 11392880 1 1025260488 99 str
4 585 0 1963224 0 1027223712 99 dict of module
5 1712 0 1799552 0 1029023264 99 dict (no owner)
6 13606 0 1741568 0 1030764832 99 types.CodeType
7 13355 0 1602600 0 1032367432 99 function
8 1494 0 1348088 0 1033715520 99 type
9 1494 0 1300752 0 1035016272 100 dict of type
<691 more rows. Type e.g. '_.more' to view.>
さて、私の記憶は次のものに奪われています:
タプルの 462 MB (え?)
412 MB のフロート (何?)
92 MB のリスト (わかりました、これは理にかなっています。2*46MB = 92)
私のリストは事前に割り当てられているので、過剰な割り当てが行われているとは思いません。
質問:
これら 2 つの非常によく似たリストで使用されるメモリの量がなぜそれほど異なるのでしょうか?
オーバーヘッドがあまりないリストを作成する別の方法はありますか?
そのメモリをすべて解放する方法はありますか?
注: ディスクに保存したり、array.array、numpy、pandas データ構造を使用したりすることはお勧めしません。これらはすべて素晴らしいオプションですが、この質問はそれらに関するものではありません。この質問は、単純な古いリストに関するものです。
Python 3.3 で同様のコードを試しましたが、結果は同じです。
同様の問題を抱えている人がいます。いくつかのヒントが含まれていますが、同じ質問ではありません。
皆さん、ありがとうございました!