7

Python がスタックとヒープを管理する方法を理解しようとしています。だから私はいくつかの「悪い」プログラミングを行い、スタックオーバーフローとヒープオーバーフローを引き起こしたいと思っていました。私が理解していないのは、たとえば文字列がスタックに移動し、他のすべてがヒープに移動する理由です。設計者の同意だけですか?例は正しいですか?私が読んだことから、オブジェクト指向であるため、Pythonのすべてがヒープで生成されますよね?

EDITED:Cのような言語のスタックは固定長ですが、PythonではAnycornが答えで言ったようにスタックも動的に割り当てられると思います。そのため、大きな文字列 (スタック上) またはリスト (ヒープ上) の両方を試すと、メモリもいっぱいになります。私が間違っている場合は、私を修正してください。ありがとう

http://docs.python.org/c-api/memory.htmlから

Python でのメモリ管理には、すべての Python オブジェクトとデータ構造を含むプライベート ヒープが含まれます。このプライベート ヒープの管理は、Python メモリ マネージャーによって内部的に保証されます。Python メモリ マネージャーには、共有、セグメント化、事前割り当て、キャッシュなど、さまざまな動的ストレージ管理の側面を処理するさまざまなコンポーネントがあり ます。

最低レベルでは、未加工のメモリ アロケータが、オペレーティング システムのメモリ マネージャと対話することで、すべての Python 関連データを格納するための十分なスペースをプライベート ヒープに確保します。raw メモリ アロケータの上に、いくつかのオブジェクト固有のアロケータが同じヒープ上で動作し、すべてのオブジェクト タイプの特性に適合する個別のメモリ管理ポリシーを実装します。

下記は用例です。それらをPythonの公式ビジュアライザーにコピーして貼り付けることができますが、値が小さいと実行されません...

スタック オーバーフローの場合:

import time
word = "test "
x = word*1000000000
time.sleep(10)
print ("this message wont appear if stack overflow has occurred!") 

私は得る

x = word*1000000000
MemoryError

ゼロを1つ削除すると実行されます。使用するとメモリ使用量が最大になりx = word*500000000 ますスタックが動的に割り当てられているため、スタックオーバーフローを発生させることはできませんか?

ヒープ オーバーフローの場合:

i = 10000
test_list = [0]
while i > 0 :
    test_list [:0] = test_list #insert a copy of itself at the beginning
    i -= 1

今私が理解していないのは、ガベージコレクターがプログラムでどのようにキックするかです.動的に割り当てられるため、スタックとヒープの両方で実行されますか? O/Sメモリマネージャーが原因ですか?これらのことは、python プログラミング言語の特徴について何を教えてくれますか? これは「動的言語」または「解釈された」という用語を正当化しますか? 長い質問で申し訳ありませんが、私の心の中でいくつかのことを明確にする必要があります. 前もって感謝します!

編集済み
私が探していたものを見つけました: sys.setrecursionlimit(N)システムが実際に処理できるよりも大きい N の値で呼び出し、その深さまで再帰しようとすると、「実際の」スタック オーバーフローが発生する可能性があります。ある時点で、システムのスタック スペースが不足し、Python インタープリターがクラッシュします。

4

2 に答える 2

7

Python では、他の言語と同様に、無限に再帰的な関数を作成することで、非常に簡単にスタック オーバーフローを引き起こすことができます。これは、再帰的であること以外に実際には何もする必要がないため、Python の方が簡単です。

>>> def foo():
...     return foo()
... 

>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  .......
  File "<stdin>", line 2, in foo
RuntimeError: maximum recursion depth exceeded
>>> 

ヒープに関しては、ガベージ コレクターによって管理されます。多くのオブジェクトを割り当てることができ、最終的にはヒープ スペースが不足し、Python は を発生MemoryErrorさせますが、かなりの時間がかかります。質問の「スタックオーバーフロー」の例で実際にそれを行いました。スタックに文字列への参照を保存しました。この文字列は、プロセスで使用できるすべての空きメモリを占有しました。経験則として、Python は、サイズを保証できない値について、スタック上のヒープ構造への参照を格納します。

すべてがどのように機能するかについては、最初の例から、Python には呼び出しスタックの深さに制限が組み込まれていることがわかります。ただし、ヒープ領域に使用できるメモリの量は OS によって定義され、多くの要因に依存します。

これらは、エラー自体に関する情報については、Python ドキュメントの適切な部分である必要があります。

于 2012-09-30T00:22:49.683 に答える
5

間違っている場合は修正してください:

私の知る限り、実際のスタックの実装に関しては、Python スタック (デフォルトのディストリビューション) は実際にはヒープ メモリ (で割り当てられたメモリ) に基づいていますmalloc。したがって、スタック オーバーフローは発生しませんが、メモリ不足になる可能性があります。あなたが見たコンピュータの速度低下は、メモリがディスクにスワップされているためであり、非常に遅い手順です.

一般に、インタープリター/バイトコンパイル言語がスタックをどのように実装するかはわかりませんが、ほとんどの場合、スタックメモリに実装されていないため、スタックオーバーフローを引き起こすことはできません. を使用して Python を実装することは可能allocaですが、なぜですか?

参照。CPython - 内部的に、スタックとヒープには何が保存されていますか?

機械語にコンパイルされるコンパイル済み言語、C++、Fortran などで同じ実験を試してください。

于 2012-09-26T22:42:22.703 に答える