web-dev-qa-db-ja.com

352GB NumPy ndarrayを8GBメモリのmacOSコンピューターで使用できるのはなぜですか?

import numpy as np

array = np.zeros((210000, 210000)) # default numpy.float64
array.nbytes

上記のコードをmacOS搭載の8GBメモリMacBookで実行しても、エラーは発生しません。しかし、Windows 10を搭載した16 GBのメモリPC、12 GBのメモリUbuntu Ubuntuラップトップ、または128 GBのメモリLinuxスーパーコンピューターで同じコードを実行すると、PythonインタープリターがMemoryErrorを発生させます。すべてのテスト環境には64ビットPython 3.6または3.7がインストールされています。

25
Blaise Wang

@ Martijn Pieters 'answer は正しい方向に進んでいますが、完全に正しくはありません。これはメモリ圧縮とは関係ありませんが、代わりに virtual memory と関係しています。

たとえば、マシンで次のコードを実行してみてください。

_arrays = [np.zeros((21000, 21000)) for _ in range(0, 10000)]
_

このコードは32TiBのメモリを割り当てますが、エラーは発生しません(少なくともLinuxでは発生しませんでした)。 htopを確認すると、次のように表示されます。

_  PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
31362 user       20   0 32.1T 69216 12712 S  0.0  0.4  0:00.22 python
_

これは、OSが 仮想メモリのオーバーコミット に完全に対応しているためです。必要になるまで、実際にはページを物理メモリに割り当てません。それが機能する方法は:

  • callocは、使用するメモリをOSに要求します
  • oSはプロセスのページテーブルを調べ、割り当て可能なメモリのチャンクを見つけます。これは高速な操作であり、OSはメモリアドレス範囲を内部データ構造に格納するだけです。
  • プログラムはアドレスの1つに書き込みます。
  • oSは ページフォールト を受け取ります。この時点で、OSはページを調べて実際に物理メモリに割り当てます。 通常、ページは数KiBのサイズです
  • oSは制御をプログラムに渡し、プログラムは中断に気付くことなく処理を続行します。

Linuxでは、単一の巨大な配列を作成することはできません。デフォルトでは "ヒューリスティックアルゴリズムが適用され、十分なメモリが利用可能かどうかを判断します。"@ Martijn Pietersに感謝! )私のシステムでのいくつかの実験は、私にとって、カーネルが_0x3BAFFFFFF_バイト以上を提供することを望まないことを示しています。ただし、_echo 1 | Sudo tee /proc/sys/vm/overcommit_memory_を実行して、OPでプログラムを再試行すると、正常に動作します。

面白くするには、arrays = [np.ones((21000, 21000)) for _ in range(0, 10000)]を実行してみてください。スワップ圧縮を使用するMacOまたはLinuxでも、メモリ不足エラーが必ず発生します。はい、特定のOSはRAMを圧縮できますが、メモリ不足にならないレベルまでRAMを圧縮できません。

23
user60561