2015-10-23 18 views
6

BytearrayとPythonのリストのメモリ管理がどのように異なるのか不思議です。BytearrayとPythonのリストの違い

私はDifference between bytearray and listのようないくつかの質問を見つけましたが、正確には私の質問に答えていません。

私の質問に正確...

from array import array 
>>> x = array("B", (1,2,3,4)) 
>>> x.__sizeof__() 
36 
>>> y = bytearray((1,2,3,4)) 
>>> y.__sizeof__() 
32 
>>> z = [1,2,3,4] 
>>> z.__sizeof__() 
36 

たちは、リスト/ array.array(4つの要素のための36バイト)とバイト配列とのサイズの違いがある見ることができるように(4つの要素のための32のバイト)。誰かがなぜ私にこのことを説明することができますか?バイト配列は、4要素(4 * 8 == 32)のメモリのうち、32バイトを占有していますが、これはlistとarray.arrayのためにどう解釈できますか?

# Lets take the case of bytearray (which makes more sense to me at least :p) 
for i in y: 
     print(i, ": ", id(i)) 

1 : 499962320 
2 : 499962336 #diff is 16 units 
3 : 499962352 #diff is 16 units 
4 : 499962368 #diff is 16 units 

各要素のみ8バイトを占有する場合、なぜ2つの隣接する要素間の差は、ここで16単位だけ異なるん。これは、各メモリアドレスポインタがニブルを指していることを意味しますか?

また、整数のメモリ割り当ての基準は何ですか?私はPythonが整数の値に基づいてより多くのメモリを割り当てることを読んでいます(私が間違っていれば私を修正します)。

例:Pythonはメモリを割り当てる基準が何であるかを

>>> y = 10 
>>> y.__sizeof__() 
14 
>>> y = 1000000 
>>> y.__sizeof__() 
16 
>>> y = 10000000000000 
>>> y.__sizeof__() 
18 

Cは8バイトしか占めません(私のものは64ビットマシンです)。それらが完全に整数の範囲の下にあるとき(2 ** 64)

メタデータ:

Pythonのバージョン:'3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)]'

マシンアーチ: 64ビット

PS:親切にPythonのメモリ管理がある良い記事に私を導きます説明が良い。私はこれらのことを理解するのに約1時間を費やしていたので、この質問をSOでお願いしました。 :(

+2

良い質問、upvoted。私のLinux Xubuntu 64ビットマシンでCPython 3.4.3 '' y = 1M'、 '32'の' '.__ sizeof __()' 'は' 'y = 'y = 10000000000000'の場合 – Pynchia

+0

こんにちは@Pynchia、私のマシンは64ビットですが、Mineは32ビットのPythonです。私は確信していませんが、それが理由かもしれません。明確にするのを待つことができます。 –

答えて

1

私は主張していないよ、これは完全な答えですが、いくつかのヒントは、このことを理解することにあります。

bytearrayが、バイトのシーケンスであるとlistだから[1,2,3]実際にメモリポインタを保持している。オブジェクト参照のシーケンスであります別の場所にメモリに格納されている。リスト構造の総メモリ消費量を計算するには、これらの整数に、我々はこれを行うことができます(私はそれが__sizeof__プラスGCのオーバーヘッドを呼んだ、どこでもさらにsys.getsizeofを使用しています)

>>> x = [1,2,3] 
>>> sum(map(getsizeof, x)) + getsizeof(x) 
172 

結果がかもしれd異なったマシンでifferent。

はまた、これを見て:

リストは変更可能であるためだ
>> getsizeof([]) 
64 

。高速になるように、この構造体はオブジェクトへの参照(およびリストの長さなどのメタのためのいくつかのストレージ)を格納するために、ある程度のメモリの範囲を割り当てます。アイテムを追加すると、次のメモリセルはそれらのアイテムへの参照で埋められます。新しいアイテムを格納する余地がないときは、新しいより大きな範囲が割り当てられ、存在するデータはそこにコピーされ、古いデータは解放されます。これは動的配列と呼ばれます。

このコードを実行すると、この現象が発生することがあります。

import sys 
data=[] 
n=15 
for k in range(n): 
    a = len(data) 
    b = sys.getsizeof(data) 
    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b)) 
    data.append(None) 

私の結果:

Length: 0; Size in bytes: 64 
Length: 1; Size in bytes: 96 
Length: 2; Size in bytes: 96 
Length: 3; Size in bytes: 96 
Length: 4; Size in bytes: 96 
Length: 5; Size in bytes: 128 
Length: 6; Size in bytes: 128 
Length: 7; Size in bytes: 128 
Length: 8; Size in bytes: 128 
Length: 9; Size in bytes: 192 
Length: 10; Size in bytes: 192 
Length: 11; Size in bytes: 192 
Length: 12; Size in bytes: 192 
Length: 13; Size in bytes: 192 
Length: 14; Size in bytes: 192 

我々は、8つのメモリ・アドレス(64ビット毎)を格納するために使用された64のバイトがあることがわかります。

bytearray()とほとんど同じです(2行目をdata = bytearray()に変更し、最後の1を追加してください)。

Length: 0; Size in bytes: 56 
Length: 1; Size in bytes: 58 
Length: 2; Size in bytes: 61 
Length: 3; Size in bytes: 61 
Length: 4; Size in bytes: 63 
Length: 5; Size in bytes: 63 
Length: 6; Size in bytes: 65 
Length: 7; Size in bytes: 65 
Length: 8; Size in bytes: 68 
Length: 9; Size in bytes: 68 
Length: 10; Size in bytes: 68 
Length: 11; Size in bytes: 74 
Length: 12; Size in bytes: 74 
Length: 13; Size in bytes: 74 
Length: 14; Size in bytes: 74 

違いは、メモリがポインタではなく実際のバイト値を保持するために使用されている点です。

あなたがさらに調査するのに役立つ希望。

+0

こんにちは@ anti1869、ご意見ありがとうございます。その非常に網羅的で有用なものです。しかし、私はあなたのコメントに次の質問があります。私はここにすべての情報を追加することができませんので、下に別のコメントを追加することはできません。ありがとう –

+0

あなたの説明によると、リストのために理解されていますが、なぜバイト配列のサイズは56で始まったのですか?また、なぜ64と56の場合は、最初のサイズの詳細情報を与えることができれば嬉しいでしょう。ありがとう –

+0

そのデータ構造のソースコードをチェックアウトします。そこには内部コンテナの構造と初期化時にメモリを割り当てるものが表示されます。また、成長アルゴリズムが非常にはっきりと見える。 https://github.com/python/cpython/blob/master/Objects/listobject.c – anti1869

関連する問題