7

我试图了解 python 如何管理堆栈和堆。所以我想做一些“糟糕”的编程并导致堆栈溢出和堆溢出。我不明白为什么字符串例如进入堆栈而所有其他字符串进入堆。仅仅是设计师的约定吗?这些例子是否正确?从我读过的内容来看,python 中的所有内容都是在堆中生成的,因为它是面向对象的,对吧?

已编辑:我认为像 C 这样的语言中的堆栈具有固定长度,但在 python 中,即使堆栈是动态分配的,正如 Anycorn 在他的回答中所说的那样。这就是为什么如果我同时尝试大字符串(在堆栈上)或列表(在堆上),我也会获得完整的内存。如果我错了,请纠正我。谢谢

来自http://docs.python.org/c-api/memory.html

Python 中的内存管理涉及一个包含所有 Python 对象和数据结构的私有堆。这个私有堆的管理由 Python 内存管理器在内部确保。Python 内存管理器具有处理各种 动态存储管理方面的不同组件,例如共享、分段、预分配或缓存。

在最低级别,原始内存分配器通过与操作系统的内存管理器交互来确保私有堆中有足够的空间来存储所有与 Python 相关的数据。在原始内存分配器之上,几个特定于对象的分配器在同一个堆上运行,并实施适应每种对象类型特性的不同内存管理策略。

这里有些例子。您可以将它们复制粘贴到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

如果我删除一个零,它就会运行。我使用时获得最大内存使用量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

现在我不明白垃圾收集器是如何在程序中运行的。它是否在堆栈和堆上都运行,因为它们都是动态分配的?是因为操作系统内存管理器吗?这些东西告诉我们关于 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 会引发 a MemoryError,但这需要相当长的时间。您实际上是在问题中的“堆栈溢出”示例中做到了这一点。您在堆栈上存储了对字符串的引用,该字符串占用了进程可用的所有空闲内存。根据经验,Python 会在堆栈上存储对任何无法保证其大小的值的堆结构的引用。

至于它是如何工作的,从第一个示例中您可以看到 python 对调用堆栈的深度有一个内置限制,它不会超过。然而,可用于堆空间的内存量由操作系统定义,并且取决于许多因素。

这些应该是 python 文档的适当部分,用于获取有关错误本身的信息:

于 2012-09-30T00:22:49.683 回答
5

如果有错误请纠正我:

据我所知,当涉及到实际的堆栈实现时,python 堆栈(在默认分布中)实际上是基于堆内存(用 分配的内存malloc)。所以你不能导致堆栈溢出,但你可能会耗尽内存。您看到的计算机速度变慢是因为内存正在交换到磁盘,过程非常缓慢。

通常,您不知道解释/字节编译语言如何实现其堆栈,但最喜欢的是它没有在堆栈内存中实现,因此您不会导致堆栈溢出。可以使用 Python 来实现alloca,但是为什么呢?

参照。CPython - 在内部,堆栈和堆中存储了什么?

尝试使用编译为机器代码的编译语言、C++、Fortran 等进行相同的实验。

于 2012-09-26T22:42:22.703 回答