3

GAE にはさまざまな制限があり、そのうちの 1 つはメモリの割り当て可能な最大ブロックのサイズが 1Mb に達することです (現在は 10 倍ですが、問題は変わりません)。この制限は、CPython が要素ポインターに連続したメモリ ブロックを割り当てようとするため、list() にいくつかの項目を超える数を配置できないことを意味します。巨大な list() を持つことはプログラミングの悪い習慣と見なされる可能性がありますが、プログラム自体に巨大な構造が作成されていなくても、CPython は舞台裏でいくつかを維持しています。

CPython は、オブジェクトの単一のグローバル リストまたは何かを維持しているようです。つまり、多くの小さなオブジェクトを持つアプリケーションは、ますます大きな単一のメモリ ブロックを割り当てる傾向があります。

最初のアイデアは gc で、それを無効にするとアプリケーションの動作が少し変わりますが、それでもいくつかの構造は維持されます。

問題が発生する最も単純な短いアプリケーションは次のとおりです。

a = b = []
number_of_lists = 8000000
for i in xrange(number_of_lists):
    b.append([])
    b = b[0]

アプリケーションに多くのオブジェクトがある場合、CPython が巨大な内部構造を割り当てないようにする方法を教えてもらえますか?

4

4 に答える 4

8

32ビットシステムでは、作成する8000000リストのそれぞれが、リストオブジェクト自体に20バイトを割り当て、さらにリスト要素のベクトルに16バイトを割り当てます。したがって、少なくとも(20 + 16)* 8000000 = 20168000000バイト、約20GBを割り当てようとしています。そして、それは、システムmallocが要求されたのとまったく同じ量のメモリのみを割り当てる場合の最良のケースです。

リストオブジェクトのサイズを次のように計算しました。

  • 2PyListObject構造自体のポインタ(listobject.hを参照)
  • 1つのポインタとリストオブジェクトPy_ssize_tの一部用のポインタ( object.hを参照)PyObject_HEAD
  • 1つPy_ssize_tPyObject_VAR_HEAD(object.hにもあります)

リスト要素のベクトルは、追加のたびにサイズを変更する必要がないように、わずかに割り当て超過になっています。listobject.cのlist_resizeを参照してください。サイズは0、4、8、16、25、35、46、58、72、88、...です。したがって、1要素リストは4要素用のスペースを割り当てます。

あなたのデータ構造はやや病的な例であり、可変サイズのリストオブジェクトを利用せずに代償を払っています-すべてのリストには単一の要素しかありません。リストの代わりにタプルを使用することで12バイトの過剰割り当てを回避できますが、メモリ消費をさらに削減するには、使用するオブジェクトの数が少ない別のデータ構造を使用する必要があります。あなたが何を達成しようとしているのかわからないので、より具体的にするのは難しいです。

于 2009-02-21T13:43:26.293 に答える
0

で何を達成しようとしていますか

a = b = []

b = b[0]

声明?Python でそのようなステートメントを見るのは確かに奇妙です。なぜなら、それらはあなたが素朴に期待することをしないからです: その例では、aとは同じbリストの 2 つの名前です(C のポインターを考えてください)。このように多くの操作を行っていると、ガベージ コレクター (および自分自身!) を混乱させるのは簡単です。

そのコードが実行しているように見えることをなぜ実行したいのかを知らずに、そのコードの何が問題なのかを診断することは困難です。確かに、それはインタープリターの奇妙さを少し露呈しています...しかし、あなたは奇妙な方法で問題に取り組んでいると思います.よりPython的なアプローチはより良い結果をもたらすかもしれません.

于 2009-02-21T11:20:33.237 に答える
0

私はあなたが何を求めているのか少し混乱しています。このコード例では、参照を実際に削除することは決してないため、ガベージ コレクションを行うべきではありません。a の最上位リストへの参照を保持しており、その中にネストされたリスト (反復ごとに b に保持されている) を追加しています。「a =」を削除すると、参照されていないオブジェクトができます。

編集: 最初の部分に対応して、はい、Python はオブジェクトのリストを保持しているため、何を選別するかを知ることができます。それがすべての質問ですか?そうでない場合は、質問にコメント/編集してください。ギャップを埋めるために最善を尽くします.

于 2009-02-21T10:47:02.053 に答える
0

お気づきのように、Python には独自のアロケーターがあります。構成ステップで --without-pyalloc を使用して無効にすることができます。

ただし、最大のアリーナは 256KB であるため、問題にはなりません。--with-pydebug を使用して、デバッグを有効にして Python をコンパイルすることもできます。これにより、メモリ使用量に関する詳細情報が得られます。

私はあなたの予感を疑っており、oefe の診断は正しいと確信しています。リストは連続したメモリを使用するため、リストがシステム アリーナに対して大きくなりすぎると、うまくいきません。本当に冒険好きなら、PyList を再実装して複数のブロックを使用することができますが、Python のさまざまなビットが連続したデータを想定しているため、これは大変な作業になります。

于 2009-02-21T17:43:43.580 に答える