<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 18 October 2017 at 21:38, Steven D'Aprano <span dir="ltr"><<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> But should it be fixed in list or in count?<br>
<br>
Neither. There are too many other places this can break for it to be<br>
effective to try to fix each one in place. <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
e.g. set(xrange(2**64)), or tuple(itertools.repeat([1]))<br></blockquote><div><br></div><div>A great many of these call operator.length_hint() these days in order to make a better guess as to how much memory to pre-allocate, so while that still wouldn't intercept everything, it would catch a lot of them.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Rather, I think we should set a memory limit that applies to the whole<br>
process. Once you try to allocate more memory, you get an MemoryError<br>
exception rather than have the OS thrash forever trying to allocate a<br>
terabyte on a 4GB machine.<br>
<br>
(I don't actually understand why the OS can't fix this.)<br></blockquote><div><br></div><div>Trying to allocate enormous amounts of memory all at once isn't the problem, as that just fails outright with "Not enough memory":</div><div><br></div><div>    >>> data = bytes(2**62)<br>    Traceback (most recent call last):<br>      File "<stdin>", line 1, in <module><br>    MemoryError<br></div><div><br></div><div>The machine-killing case is repeated allocation requests that the operating system *can* satisfy, but require paging almost everything else out of RAM. And that's exactly what "list(infinite_iterator)" entails, since the interpreter will make an initial guess as to the correct size, and then keep resizing the allocation to 125% of its previous size each time it fills up (or so - I didn't check the current overallocation factor) .<br></div><br><div>Per-process memory quotas *can* help avoid this, but enforcing them requires that every process run in a resource controlled sandbox. Hence, it's not a coincidence that mobile operating systems and container-based server environments already work that way, and the improved ability to cope with misbehaving applications is part of why desktop operating systems would like to follow the lead of their mobile and server counterparts :)<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
So here is my suggestion:<br>
<br>
1. Let's add a function in sys to set the "maximum memory" available,<br>
for some definition of memory that makes the most sense on your<br>
platform. Ordinary Python programmers shouldn't have to try to decipher<br>
the ulimit interface.<br></blockquote><div><br></div><div>Historically, one key reason we didn't do that was because the `PyMem_*` APIs bypassed CPython's memory allocator, so such a limit wouldn't have been particularly effective.</div><div><br></div><div>As of 3.6 though, even bulk memory allocations pass through pymalloc, making a Python level memory allocation limit potentially more viable (since it would pick up almost all of the interpeter's own allocations, even if it missed those in extension modules): <a href="https://docs.python.org/dev/whatsnew/3.6.html#optimizations">https://docs.python.org/dev/whatsnew/3.6.html#optimizations</a><br></div><div><br></div>Cheers,</div><div class="gmail_quote">Nick.<br clear="all"></div><br>-- <br><div class="gmail_signature">Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>   |   Brisbane, Australia</div>
</div></div>