[Tutor] Question about the memory manager

Tim Peters tim.peters at gmail.com
Sun Jan 10 11:54:10 EST 2016


[Albert-Jan Roskam <sjeik_appie at hotmail.com>]
> I just found a neat trick to free up an emergency stash of memory in
> a funtion that overrides sys.excepthook. The rationale is that all
> exceptions, including MemoryErrors will be logged.
> The code is below. My question: is that memory *guaranteed* to be
> freed right after the 'del' statement? Or should one call gc.collect to
> be really sure?
>
> rainydayfund = [[] for x in xrange(16*1024)] # or however much you need
> def handle_exception(e):
>     global rainydayfund
>     del rainydayfund
> ... etc, etc ...
> http://stackoverflow.com/questions/1235349/python-how-can-i-handle-any-unhandled-exception-in-an-alternative-way

This works fine in all versions of CPython (the C implementation of
Python distributed by python.org) to date.  That's because:

1. All versions of CPython rely primarily on reference counting (`gc`
is only needed to reclaim garbage containing reference cycles).  An
object is released immediately when its reference count falls to 0.

2. There is only one reference to the big list there (via the global
`raindydayfund`), so the memory becomes garbage immediately upon
executing the `del`.

3. Similarly, that giant list holds the only references to the masses
of distinct empty lists it contains, so they also become garbage
immediately upon the giant list becoming garbage.

4. CPython doesn't happen to stick garbage lists in, e.g., some
internal free list reusable only for new list objects - it actually
releases the memory for garbage lists.  Kinda ;-)

#2 and #3 are necessarily true.  #1 is true in CPython, but not in all
implementations of Python.

#4 is where things _might_ change even in CPython, but it's very
unlikely to change.  As is, it would take a small book to flesh out
what "Kinda ;-)" means, exactly.  Memory management is complex, with
many layers, involving many details.

If you can live with all that, I'd suggest a more straightforward way
of setting it up, like:

rainydayfund  = b"x" * N

where `N` is the number of bytes you want to reserve.  That is, create
a giant bytestring containing the number of "emergency bytes" you
need.  If N is large enough, that will avoid CPython's "small object
allocator" and CPython's "arena allocator", getting the memory
directly from (and returning the memory directly to) the OS.  The
fewer layers that get involved, the fewer layers that _may_ surprise
you by changing behavior in the future.


More information about the Tutor mailing list