9

I am trying to understand how python manages stack and heap. So I wanted to do some "bad" programming and cause a stack overflow and heap overflow. What I don't understand is why strings for example go to stack while all others go to heap. Is it just agreement of the designers? Are the examples correct? From what I have read everything in python is generated in heap since its object oriented, right?

EDITED: I suppose that stack in languages like C have a fixed length but in python even the stack is dynamically allocated as Anycorn said in his answer. Thats why I also get full memory if I try both a large string (on stack) or a list (on heap). If i am wrong please correct me. Thanks

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

Memory management in Python involves a private heap containing all Python objects and data structures. The management of this private heap is ensured internally by the Python memory manager. The Python memory manager has different components which deal with various dynamic storage management aspects, like sharing, segmentation, preallocation or caching.

At the lowest level, a raw memory allocator ensures that there is enough room in the private heap for storing all Python-related data by interacting with the memory manager of the operating system. On top of the raw memory allocator, several object-specific allocators operate on the same heap and implement distinct memory management policies adapted to the peculiarities of every object type.

Here are some examples. You can copy paste them in Python official visualizer but with smaller values cause it wont run...

For stack overflow:

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

I get

x = word*1000000000
MemoryError

If I delete one zero it runs. I get max memory usage when I use x = word*500000000 So I can't make a stack overflow because even the stack is dynamically allocated?

For heap overflow:

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

Now what I don't understand is how the garbage collector kicks in the programs.Does it run on both stack and heap since they are both dynamically allocated? Is it due to O/S memory manager? What do those things tell us about the characterization of python programming language? Does this justify the term "dynamic language" or "interpreted"? Sorry for the long question but i just need to clarify some things in my mind. Thanks in advance!

EDITED
I've found what i was looking for: You can cause a 'real' stack overflow if you call sys.setrecursionlimit(N) with a value of N larger than your system can actually handle and then try to recurse to that depth. At some point your system will run out of stack space and the Python interpreter will crash.

trincot
  • 317,000
  • 35
  • 244
  • 286
BugShotGG
  • 5,008
  • 8
  • 47
  • 63
  • 3
    String objects go on the heap as well; the visualizer is a little misleading in that respect. – Martijn Pieters Sep 26 '12 at 22:19
  • 1
    Your first example results in a memory error, not a stack overflow. – Marcin Sep 26 '12 at 22:20
  • @MartijnPieters Well Now i am more confused :( – BugShotGG Sep 26 '12 at 22:20
  • @Marcin well u can multiply it with a lower factor lets say 10000000. It works for me... – BugShotGG Sep 26 '12 at 22:21
  • 1
    @GeoPapas I'm using the same visualiser you are. Also, no stackoverflow occurs with a lower value, not least because there is no stack growth. – Marcin Sep 26 '12 at 22:22
  • 4
    I think you misunderstand what a stackoverflow is. – Anycorn Sep 26 '12 at 22:22
  • @Marcin OUPS yes in the visualizer u have to enter a small value. I run it on my pc with that big value just to see the memory peaks. Sorry. – BugShotGG Sep 26 '12 at 22:24
  • 1
    @Anycorn Well what am i missing here? :o Any help would be appreciated! – BugShotGG Sep 26 '12 at 22:25
  • @GeoPapas Nevertheless, your first example does not cause any stack growth. – Marcin Sep 26 '12 at 22:25
  • @Marcin Hmm i dont get it i run it on eclipse and i my computer froze for a while. Checked the task manager and memory was full almost 6/6 gb used. Now when i run it i get Memory error... – BugShotGG Sep 26 '12 at 22:29
  • 1
    @GeoPapas Which stackoverflow are you after? Exhausting stack memory? Or overrunning stack buffer? – Anycorn Sep 26 '12 at 22:29
  • @Anycorn well exhausting stack memory i guess... Weird... When i run the 1st program now i just get memory error. :O how can this be i just run the program before i post it here and i was watching my memory going crazy... – BugShotGG Sep 26 '12 at 22:32
  • 2
    If it used up 6GB and froze your computer, that's definitely heap memory, not stack. – abarnert Sep 26 '12 at 22:34
  • Now i got it. It should only show the message if there is space in stack. With x = word*1000000000 i get MemoryError but if u delete one zero 0 it will run. Is that ok now? – BugShotGG Sep 26 '12 at 22:39
  • But Stack Overflow was caused in 2008 by Jeff Atwood and Joel Spolsky. To try to cause it yourself would be plagiarism. – tkbx Sep 26 '12 at 22:46
  • @tkbx Well as i said in the question i am kinda confused how stack and heap is implemented in python. I am new in python. :) – BugShotGG Sep 26 '12 at 22:48
  • 2
    @GeoPapas you completely missed the joke :P – tkbx Sep 26 '12 at 23:09

2 Answers2

8

You can cause a stack overflow quite easily in python, as in any other language, by building an infinately recursive funcion. This is easier in python as it doesn't actually have to do anything at all other than be recursive.

>>> 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
>>> 

As for the heap, that is managed by a garbage collector. You can allocate lots of objects and eventually run out of heap space and Python will raise a MemoryError, but it's going to take a fair amount of time. You actually did that with your 'stack overflow' example in the question. You stored a reference to a string on the stack, this string took up all the free memory available to the process. As a rule of thumb, Python stores a reference to a heap structure on the stack for any value that it can't guarantee the size of.

As for how it all works, from the fist example you can see that python has a built-in limit to the depth of the call stack that it will not exceed. The amount of memory available for heap space is defined by the OS however and will depend upon many factors.

These are should be the appropriate parts of the python docs for infomation on the errors themselves:

Will
  • 4,585
  • 1
  • 26
  • 48
  • So if we create a large string it is also stored in the heap as well? I thought strigns were stored in stack and thats one reason for being immutable. I ve seen that in the python visualizer where if u create strings they are placed in frames which implies stack. hmmm – BugShotGG Sep 30 '12 at 11:03
  • Yes and no, although python strings are immutable sequences there is no specific way in which they must be stored. You can't store them in the stack frame and must store them as a reference however otherwise you wouldn't be able to return a string from a method as it's data would go out of scope when the function returned. (This is a simplification. There are lots of ways to implement a Python intepreter). – Will Sep 30 '12 at 12:42
  • I think this is a confusing grey area between how the string type is implemented and how the python interpreter presents it to the program. – Will Sep 30 '12 at 12:58
  • Well after so many answers i still cant see what is getting stored in stack and what not. :( Still with the recursion example u cant achieve stack overflow as it doesnt eve run it just throws the error and memory is unchanged :o . To sum up.. only names are stored in stack or are they objects in heap as well? – BugShotGG Oct 01 '12 at 19:43
  • 1
    this is up to the implementation but a typical one will store a small structure for each local variable in the function stack frame. this frame is allocated on the heap. the contents of this structure can then either contain all the content of the value, e.g for an integer, or a reference to some other storage that contains the rest. these would be stored on the heap. strings are stored slightly differently in CPython so that it has to do fewer copies but the memory for them still comes from the heap. – Will Oct 01 '12 at 20:20
  • simple and clean answer for what i was looking for. Sometimes 2-3 lines answers are the best :) Thanks – BugShotGG Oct 01 '12 at 20:21
6

please correct me if wrong:

As far as I know, when it comes to actual stack implementation, the python stack (in the default distribution) is actually based in the heap memory (memory allocated with malloc). So you cannot cause the stack overflow, but you can run out of memory. The computer slowdown you seen is because memory is being swapped to disk, very slow procedure.

generally, you have no idea how the interpreted/byte-compiled language implements its stack, but most like it is not implemented in the stack memory, so you cannot cause stack overflow. it is possible to implement Python using alloca, but why?

Cf. CPython - Internally, what is stored on the stack and heap?

Try the same experiment with compiled language, C++, Fortran, etc. which compiles to machine code.

Community
  • 1
  • 1
Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • 1
    So we actually have a heap where within it is implemented both stack and heap? :o – BugShotGG Sep 26 '12 at 22:49
  • 3
    @GeoPapas you have to differentiate between program callstack and the actual machine memory stack when it comes to non-compiled languages – Anycorn Sep 26 '12 at 22:52
  • 1
    Ok i think i am clearing things up here. So in contrast to the classic stack in C where we have a fixed length in Python even the stack is treated like it was a heap which means that it is dynamically allocated as well? Is that correct? Thanks in advance. Waiting for a reply to clarify things :D – BugShotGG Sep 27 '12 at 09:01
  • 1
    *"you cannot cause the stack overflow, but you can run out of memory."* -> Incorrect. Function calls in Python invoke [callfunction()](https://github.com/python/cpython/blob/520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb/Python/ceval.c#L4518) in C, which recurses the evaluator...the next recursion will see another callfunction() pile up on the C stack. And there is [no platform independent way](https://stackoverflow.com/q/7067357/) for a standard C program to detect a limit. Python just crosses its fingers and hopes setrecursionlimit() was low enough to avoid a stackoverflow, but it may not be. – HostileFork says dont trust SE Mar 13 '18 at 04:53