2016-04-07 16 views
2

3GBのXMLファイルを処理しようとしていて、ファイルを読み込んで辞書にデータを格納するループの途中でmemoryerrorを取得しています。大きな辞書を作成するPython memoryerror

class Node(object): 
    def __init__(self, osmid, latitude, longitude): 
     self.osmid = int(osmid) 
     self.latitude = float(latitude) 
     self.longitude = float(longitude) 
     self.count = 0 


context = cElementTree.iterparse(raw_osm_file, events=("start", "end")) 
context = iter(context) 
event, root = context.next() 

for event, elem in context: 
    if event == "end" and elem.tag == "node": 
     lat = float(elem.get('lat')) 
     lon = float(elem.get('lon')) 
     osm_id = int(elem.get('id')) 
     nodes[osm_id] = Node(osm_id, lat, lon) 
     root.clear() 

私は反復的な解析方法を使用しているため、ファイルを読むことに問題はありません。私はちょうど後で処理するために辞書にデータを保存したいのですが、辞書が大きくなりすぎているようです。プログラムの後半で私はリンクを読み込み、リンクによって参照されるノードがノードの最初のバッチにあったかどうかをチェックする必要があります。そのため、それらを辞書に格納しています。

どのようにすれば、メモリフットプリントを大幅に減らすことができますか(スクリプトは仕上げに近づいていないので、ビットとピースを削っても効果がありません)、またはPythonで使用できるメモリの量を大幅に増やすことができますか? Pythonのようなメモリ使用状況を監視すると、約1950 MBになってしまい、コンピュータにはまだ約6 GBのRAMがあります。

+2

64ビットPythonを実行していますか? –

+0

ああシュート、私は思ったが、ちょうどチェックして、私は実際に32を使用している。それは32とメモリ使用量にハードキャップがありますが、64ではなく、私の理解ですよね? – wmebane

+1

64ビットのハード・キャップもありますが、テラバイトの倍数なので、ヒットする可能性は非常に低いです。 –

答えて

3

Nodeのトンが作成されていると仮定すると、__slots__を使用して、それぞれNodeの固定アトリビュートセットを事前に定義することが考えられます。これにより、インスタンスごとに__dict__(宣言されていない属性の作成を防ぐために)を格納するオーバーヘッドがなくなり、Nodeのメモリ使用量を〜5x(less on Python 3.3+ where shared key __dict__ reduces the per-instance memory cost for free)で簡単に削減できます。

それが行うのは簡単ですが、ちょうどにNodeの宣言を変更します。たとえば

class Node(object): 
    __slots__ = 'osmid', 'latitude', 'longitude', 'count' 

    def __init__(self, osmid, latitude, longitude): 
     self.osmid = int(osmid) 
     self.latitude = float(latitude) 
     self.longitude = float(longitude) 
     self.count = 0 

、(共有鍵辞書はすでに何かを保存する)はPython 3.5で、オブジェクトのオーバーヘッドの差はで見ることができます:

>>> import sys 
>>> ... define Node without __slots___ 
>>> n = Node(1,2,3) 
>>> sys.getsizeof(n) + sys.getsizeof(n.__dict__) 
248 
>>> ... define Node with __slots__ 
>>> n = Node(1,2,3) 
>>> sys.getsizeof(n) # It has no __dict__ now 
72 

これは、共有キー辞書付きのPython 3.5です。 Python 2では、__slots__のインスタンスごとのコストは、__slots__を除いたコストは数百バイト増加するのに対し、ポインタサイズの大きい変数はIIRCよりも大きかったです。

また、64ビットOSを使用している場合は、64ビットOSに合わせて64ビットバージョンのPythonをインストールしてください。それ以外の場合は、Pythonは〜2 GBの仮想アドレス空間に制限され、6 GBのRAMはごくわずかです。

+0

これはうまくいった!メモリ使用量を1トン削減し、64ビット版に切り替えると、まだ必要な余分なGBが得られました。ありがとう! – wmebane

関連する問題