メモリ使用量テストを複製しようとしていましたここに。
基本的に、この投稿は次のコードスニペットを与えたと主張しています。
import copy
import memory_profiler
@profile
def function():
x = list(range(1000000)) # allocate a big list
y = copy.deepcopy(x)
del x
return y
if __name__ == "__main__":
function()
呼び出す
python -m memory_profiler memory-profile-me.py
64ビットコンピューターでの印刷
Filename: memory-profile-me.py
Line # Mem usage Increment Line Contents
================================================
4 @profile
5 9.11 MB 0.00 MB def function():
6 40.05 MB 30.94 MB x = list(range(1000000)) # allocate a big list
7 89.73 MB 49.68 MB y = copy.deepcopy(x)
8 82.10 MB -7.63 MB del x
9 82.10 MB 0.00 MB return y
同じコードをコピーして貼り付けましたが、プロファイラーは
Line # Mem usage Increment Line Contents
================================================
3 44.711 MiB 44.711 MiB @profile
4 def function():
5 83.309 MiB 38.598 MiB x = list(range(1000000)) # allocate a big list
6 90.793 MiB 7.484 MiB y = copy.deepcopy(x)
7 90.793 MiB 0.000 MiB del x
8 90.793 MiB 0.000 MiB return y
この投稿は古くなっている可能性があります---プロファイラーパッケージまたはpythonが変更されている可能性があります。いずれにせよ、私の質問は、Python 3.6.x
(1)
copy.deepcopy(x)
は(上記のコードで定義されているように)自明ではない量のメモリを消費しますか?
(2)なぜ複製できなかったのですか?
(3)
x = list(range(1000000))
を繰り返した場合
del x
の後
、最初に
x = list(range(1000000))
を割り当てたのと同じ量だけメモリが増加しますか(私のコードの5行目のように)?
回答 1 件
関連記事
- RにTensorflowをインストールできません。「{PATH}のPython環境が見つかりませんでした」
- `list`へのメモリの割り当てはPythonでどのように機能しますか?リストのサイズがそのオブジェクトの合計と同じでないのはなぜですか?
- システムは、指定されたファイルを見つけることができません:Python音声認識
- 一部のrequirementstxtpython依存関係をインストールできません
- 作成前のPythonクラスタイプの使用法
- AWS Lambda Pythonレイヤーを作成するにはどうすればよいですか? (XGBoostでの使用例)
- Othelloと呼ばれるPythonでゲームを作るのは本物のゲームです。配列内の特定の値を変更することはできません
- Pythonは、リスト要素の代わりにメモリ位置を出力します
- Pythonを使用してInfluxdbv2データをクエリできないのはなぜですか?
- モードを使用してNaNを最も頻繁な列文字列値に置き換えると、PythonでFillnaを機能させることができません
copy.deepcopy()
再帰的にコピーする可変オブジェクトのみ、整数や文字列などの不変オブジェクトはコピーされません。コピーされるリストは不変の整数で構成されているため、y
コピーは同じ整数値への参照を共有することになります:そのため、コピーでは、100万の参照を持つ新しいリストオブジェクトを作成するだけで済みます。これは、Mac OS X 10.13(64ビットOS)で作成したPython 3.6で8MBを少し超えるメモリを消費するオブジェクトです。
空の
list
オブジェクトは64バイトを使用し、各参照は8バイトを使用します。Pythonリストオブジェクトは全体的にスペースを増やして
range()
を変換します リストのオブジェクトは、deepcopy
を使用する場合よりも追加の成長のために少し多くのスペースを作成します 、だからx
まだサイズが少し大きく、再度サイズ変更する前に125k個のオブジェクトを追加するスペースがあります。一方、コピーには約87k分の追加スペースしかありません。
Python 3.6では、記事の主張を再現することはできません。これは、Pythonが多くのメモリ管理の改善を見たためと、記事がいくつかの点で間違っているためです。
copy.deepcopy()
の動作 リストと整数に関しては決してcopy.deepcopy()
の長い歴史の中で変更された (1995年に追加されたモジュールの最初のリビジョンを参照してください)、メモリ数値の解釈は、Python 2.7でも間違っています。具体的には、私はできる Python 2.7を使用して結果を再現するこれは私のマシンで見たものです:
起こっているのは、Pythonのメモリ管理システムが追加の拡張のために新しいメモリチャンクを割り当てていることです。それは新しい
y
ではありません リストオブジェクトは約93MiBのメモリを使用します。これは、OSがPythonのプロセスにオブジェクトヒープ用のメモリを追加要求したときに割り当てた追加メモリにすぎません。リストオブジェクト自体はたくさん 小さい。Python 3
tracemalloc
モジュールは実際に何が起こるかについてはるかに正確です:Python 3.xのメモリマネージャーとリストの実装は、2.7のものよりもスマートです。明らかに、新しいリストオブジェクトは、
x
の作成時に事前に割り当てられた既存の利用可能なメモリに収まることができた 。手動でビルドされたPython 2.7.12 tracemallocバイナリと
memory_profile.py
への小さなパッチを使用して、Python 2.7の動作をテストできます。 。これで、Python 2.7でもより安心できる結果が得られます。著者も混乱していたことに注意してください。
(大胆な強調鉱山)。
ここでのエラーは、Pythonプロセスサイズのすべてのメモリ変更が特定のオブジェクトに直接起因すると想定することですが、メモリマネージャが(削除します!)メモリー「アリーナ」、必要に応じてヒープ用に予約されたメモリーのブロック。それが理にかなっている場合は、より大きなブロックでそうします。 PythonのマネージャーとOS
malloc
の間の相互作用に依存するため、ここでのプロセスは複雑です。 実装の詳細。著者は、Pythonのモデルに関する最新の記事を発見しました。これは、最新のものであると誤解されているものです。その記事の著者自身が、すでにこれを指摘しようとしています。 Python 2.5では、Pythonがメモリを解放しないという主張はもはや真実ではありません。厄介なのは、同じ誤解が作成者を
pickle
の使用に対して推奨するように導くことです 、しかし実際には、Python 2でさえモジュールは再帰的な構造を追跡するために少しの記帳メモリ以上を決して追加しません。私のテスト方法論については、この要点をご覧ください。cPickle
を使用する Python 2.7では、46MiBの1回限りの増加が追加されます(create_file()
を2倍に 呼び出しの結果、メモリはそれ以上増加しません)。 Python 3では、メモリの変更は完全になくなりました。Theanoチームと投稿についてダイアログを開きます。記事は間違っており、混乱を招きます。Python2.7はまもなく完全に廃止されるため、Python 3のメモリモデルに集中する必要があります。(*)
作成するとき新しいリスト
range()
から 、コピーではなく、x
を作成する場合と同様にメモリが増加します これは、新しいリストオブジェクトに加えて、新しい整数オブジェクトのセットを作成するためです。特定の小さな整数のセットは別として、Pythonはrange()
の整数値をキャッシュして再利用しません 操作。(*) 補遺:Thanoプロジェクトで課題#6619を開きました。プロジェクトは私の評価に同意し、ドキュメントからページを削除しましたが、公開バージョンはまだ更新されていません。