2013-05-11 5 views
7

私は、メモリに保持されている大きなリストからデータにアクセスすることを含むプロジェクトに取り組んでいます。リストは非常にボリュームがあるので(何百万行も)、私はどのくらいのメモリが使用されているかを見守ります。 OS Xを使用しているので、これらのリストを作成するときにアクティビティモニターを開いたままにしておきます。Pythonリストの異常なメモリ使用

リストで使用されるメモリの量は、構築方法によって大きく異なることがありますが、その理由を理解できないようです。いくつかのサンプルコードのための今すぐ

は、最初の関数は、以下のリストを作成し、すべて同じ3つの乱数でそれを埋める(私はOSX 10.8.3でPython 2.7.4を使用しています)。

以下の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メガバイトでジャンプを使用していました。

は今、次の機能のために:あなたが見ることができるように

In [4]: thing2 = make_table2(6000000) 

In [5]: sys.getsizeof(thing2) 
Out[5]: 48000072 

、二つのリストに取り込まれたメモリは同じです。彼らはまさに同じ長さなので、それは予想されます。私が期待していなかったことは、アクティビティモニターで使用されたメモリを1 GB以上にジャンプしたことです!

私はいくつかのオーバーヘッドがあると思いますが、20倍もあると思いますか? 46MBのリストでは1GB?

真剣に?

In [5]: import gc 

In [6]: gc.collect() 
Out[6]: 0 

は、それが使用されるメモリの量をゼロに違いを作っ:診断へのオーケー

、...

私が試した最初のものは、任意のゴミを収集することです。

次私はメモリが起こっている場所を確認するためにグッピーを使用:タプルのの

462メガバイト(でしょ?)

412:

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.> 

大丈夫、私の記憶が取り込まれますフロートのMB(何?)リストの

92 MB(さて、この1つは理にかなっています。2 * 46メガバイト= 92)

私のリストはあらかじめ割り当てられているので、過剰割り当てがあるとは思わない。

質問:

なぜこれほど異なるこれら2つの非常に類似したリストが使用するメモリの量は?

あまりオーバーヘッドのないリストを作成する別の方法はありますか?

メモリをすべて解放する方法はありますか?

注:ディスクに保管するか、array.arrayまたはnumpyまたはpandasデータ構造を使用することをおすすめしないでください。それらはすべて素晴らしいオプションですが、この質問はそれらに関するものではありません。この質問は普通の古いリストに関するものです。

私はPython 3.3で同様のコードを試しましたが、結果は同じです。

ここにはsimilar problemの人がいます。それはいくつかのヒントを含んでいますが、同じ質問ではありません。

ありがとうございました!

+1

あなたのサイズ×3 6000000の2D配列に興味を持っているようです。あなたはnumpyを見ましたか?(例: 'numpy.random.rand(6000000、3)') – SingleNegationElimination

答えて

8

両方の関数は、6000000個の参照のリストを作成します。

sizeof(thelist) ≅ sizeof(reference_to_a_python_object) * 6000000 

最初のリストには、同じ1組の3つの浮動小数点数に対する6000000の参照が含まれています。

第2のリストには、18000000の異なる浮動小数点数を含む6000000の異なるタプルへの参照が含まれています。

enter image description here

あなたが見ることができるように、フロートは24のバイトを取り、トリプルは(のpythonのビルドを使用して)80バイトになります。いいえ、周り以外の方法はありません。コレクターごみの中にリストをオンにする

、あなたはそれらへの参照を取り除く必要があります。

del thing1 
del thing2 
関連する問題