More details in MemoryError
I propose to add new optional attributes to MemoryError, which show how many memory was required in failed allocation and how many memory was used at this moment.
On Mon, Jan 21, 2013 at 09:20:08PM +0200, Serhiy Storchaka
I propose to add new optional attributes to MemoryError, which show how many memory was required in failed allocation and how many memory was used at this moment.
I'd very much like to see a situation when a program can survive MemoryError. Oleg. -- Oleg Broytman http://phdru.name/ phd@phdru.name Programmers don't die, they just GOSUB without RETURN.
2013/1/21 Oleg Broytman
I'd very much like to see a situation when a program can survive MemoryError.
Let's say your using an image processing program.
You have several images open on which you've been working for a couple
minutes/hours.
You open a new one, and it's so large that it results in MemoryError :
instead of just losing all your current work (yeah, the program should
support auto-save anyway, but let's pretend it doesn't), the program
catches MemoryError, and displays a popup saying "No enough memory to
process this image".
Now, sure, there are cases where an OOM condition will result in
thrashing to death, or simply because of overcommit malloc() will
never return NULL and you'll get nuked by the OOM killer, but
depending on your operating system and allocation pattern, there are
times when you can reasonably recover from a MemoryError.
Also, a memory allocation failure doesn't necessarily mean you're OOM,
it could be that youve exhausted your address space (on 32-bit), or
hit RLIMIT_VM/RLIMIT_DATA.
2013/1/21 Benjamin Peterson
What is this useful for?
Even if the exception isn't caught, if the extra information gets dumped in the traceback, it can be used for post-mortem debugging (to help distinguish between OOM, address space exhaustion, heap fragmentation, overflow in computation of malloc() argument, etc). So I think it could probably be useful, but I see two problems: - right now, the amount of memory isn't tracked. IIRC, Antoine added recently a counter for allocated blocks, not bytes - the exception is raised at the calling site where the allocation routine failed (this comes from Modules/_pickle.c): """ PyMemoTable *memo = PyMem_MALLOC(sizeof(PyMemoTable)); if (memo == NULL) { PyErr_NoMemory(); return NULL; } """ So we can't easily capture the current allocated memory and the requested memory (the former could probably be retrieved in PyErr_NoMemory(), but the later would require modifying every call site and repeating it).
There's a bigger reason memory error must be stateless: we preallocate and reuse it. -- Sent from my phone, thus the relative brevity :)
Le Tue, 22 Jan 2013 18:53:49 +1000,
Nick Coghlan
There's a bigger reason memory error must be stateless: we preallocate and reuse it.
Not anymore, it's a freelist now: http://hg.python.org/cpython/file/e8f40d4f497c/Objects/exceptions.c#l2123 The "stateless" part was bogus in Python 3, because of the embedded traceback and context. Regards Antoine.
On Tue, Jan 22, 2013 at 7:12 PM, Antoine Pitrou
Le Tue, 22 Jan 2013 18:53:49 +1000, Nick Coghlan
a écrit : There's a bigger reason memory error must be stateless: we preallocate and reuse it.
Not anymore, it's a freelist now: http://hg.python.org/cpython/file/e8f40d4f497c/Objects/exceptions.c#l2123
The "stateless" part was bogus in Python 3, because of the embedded traceback and context.
Oh cool, I forgot about that change. In that case, +0 for at least reporting how much memory was being requested for the call that failed, even if that only turns out to be useful in our own test suite. -0 for the "currently allocated" suggestion though, as I don't see how we can provide a meaningful value for that (too much memory usage can be outside of the controller of the Python memory allocator, and we don't even track our own usage all that closely in non-debug builds). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Le Tue, 22 Jan 2013 20:42:38 +1000,
Nick Coghlan
In that case, +0 for at least reporting how much memory was being requested for the call that failed, even if that only turns out to be useful in our own test suite. -0 for the "currently allocated" suggestion though, as I don't see how we can provide a meaningful value for that (too much memory usage can be outside of the controller of the Python memory allocator, and we don't even track our own usage all that closely in non-debug builds).
Windows makes it easy to retrive the current process' memory statistics: http://hg.python.org/benchmarks/file/43f8a0f5edd3/perf.py#l240 As usual, though, POSIX platforms are stupidly painful to work with: http://hg.python.org/benchmarks/file/43f8a0f5edd3/perf.py#l202 Regards Antoine.
On 22.01.13 00:12, Benjamin Peterson wrote:
Serhiy Storchaka
writes: I propose to add new optional attributes to MemoryError, which show how many memory was required in failed allocation and how many memory was used at this moment.
What is this useful for?
Bigmem testing.
On 22/01/13 09:12, Benjamin Peterson wrote:
Serhiy Storchaka
writes: I propose to add new optional attributes to MemoryError, which show how many memory was required in failed allocation and how many memory was used at this moment.
What is this useful for?
After locking up a production machine with a foolishly large list multiplication (I left it thrashing overnight, and 16+ hours later gave up and power-cycled the machine), I have come to appreciate ulimit on Linux systems. That means I often see MemoryErrors while testing. [steve@ando ~]$ ulimit -v 20000 [steve@ando ~]$ python3.3 Python 3.3.0rc3 (default, Sep 27 2012, 18:44:58) [GCC 4.1.2 20080704 (Red Hat 4.1.2-52)] on linux Type "help", "copyright", "credits" or "license" for more information. === startup script executed === py> x = [0]*1000000 py> x = [0]*123456789012 # oops what was I thinking? Traceback (most recent call last): File "<stdin>", line 1, in <module> MemoryError For interactive use, it would be really useful in such a situation to see how much memory was requested and how much was available. That would allow me to roughly estimate (say) how big a list I could make in the available memory, instead of tediously trying larger and smaller lists. Something like this could be used to decide whether or not to flush unimportant in-memory caches, compact data structures, etc., or just give up and exit. -- Steven
On Tue, Jan 22, 2013 at 11:42 PM, Steven D'Aprano
Something like this could be used to decide whether or not to flush unimportant in-memory caches, compact data structures, etc., or just give up and exit.
That's a nice idea, but unless the requested allocation was fairly large, there's a good chance you don't have room to allocate anything more. That may make it a bit tricky to do a compaction operation. But if there's some sort of "automatically freeable memory" (simple example: exception-triggered stack unwinding results in a whole bunch of locals disappearing), and you can stay within that, then you might be able to recover. Would require some tightrope-walking in the exception handler, but ought to be possible. ChrisA
On Wed, 23 Jan 2013 00:04:15 +1100
Chris Angelico
On Tue, Jan 22, 2013 at 11:42 PM, Steven D'Aprano
wrote: Something like this could be used to decide whether or not to flush unimportant in-memory caches, compact data structures, etc., or just give up and exit.
That's a nice idea, but unless the requested allocation was fairly large, there's a good chance you don't have room to allocate anything more.
I wouldn't be surprised if most cases of MemoryErrors were on fairly large allocation requests ;-) Regards Antoine.
On Wed, Jan 23, 2013 at 5:27 AM, Antoine Pitrou
On Wed, 23 Jan 2013 00:04:15 +1100 Chris Angelico
wrote: On Tue, Jan 22, 2013 at 11:42 PM, Steven D'Aprano
wrote: Something like this could be used to decide whether or not to flush unimportant in-memory caches, compact data structures, etc., or just give up and exit.
That's a nice idea, but unless the requested allocation was fairly large, there's a good chance you don't have room to allocate anything more.
I wouldn't be surprised if most cases of MemoryErrors were on fairly large allocation requests ;-)
Depends on the workflow. Something that allocates an immediate block of memory, yes, but if you're progressively building a complex structure, individual allocations mightn't themselves be significant. ChrisA
On 2013-01-22 13:04, Chris Angelico wrote:
On Tue, Jan 22, 2013 at 11:42 PM, Steven D'Aprano
wrote: Something like this could be used to decide whether or not to flush unimportant in-memory caches, compact data structures, etc., or just give up and exit.
That's a nice idea, but unless the requested allocation was fairly large, there's a good chance you don't have room to allocate anything more. That may make it a bit tricky to do a compaction operation. But if there's some sort of "automatically freeable memory" (simple example: exception-triggered stack unwinding results in a whole bunch of locals disappearing), and you can stay within that, then you might be able to recover. Would require some tightrope-walking in the exception handler, but ought to be possible.
FYI, allocating memory specially for such cases is sometimes called a "memory parachute". I wonder whether you could have a subclass of MemoryError called LowMemoryError. If allocation fails and there's a parachute, it would free the parachute and raise LowMemoryError. That would gave you a chance to tidy up before quitting or even, perhaps, free enough stuff to make a new parachute and continue working. If allocation fails and there's no parachute, it would raise MemoryError as at present. With LowMemoryError as a subclass of MemoryError, existing code would still work the same.
Le Mon, 21 Jan 2013 21:20:08 +0200,
Serhiy Storchaka
I propose to add new optional attributes to MemoryError, which show how many memory was required in failed allocation and how many memory was used at this moment.
+1 on the principle. I hope you can devise an implementation :-) Regards Antoine.
participants (9)
-
Antoine Pitrou
-
Benjamin Peterson
-
Charles-François Natali
-
Chris Angelico
-
MRAB
-
Nick Coghlan
-
Oleg Broytman
-
Serhiy Storchaka
-
Steven D'Aprano