www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is "Out of Memory" a recoverable error?

reply Walter Bright <newshound1 digitalmars.com> writes:
I asked this over on stackoverflow.com to see what people using other 
languages have to say, as well as the D community. The reason I ask is 
to see if memory allocation can be allowed in functions marked "nothrow".

http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error
Dec 02 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
In a program "Out of Memory" is recoverable, for example your program can use
several caches, buffers, and it can use data already present on disk too, or
data that can be moved on disk now.
A good program when finds an out of memory situation can clear its caches,
delete not essential data structures, and save some data on disk, to free some
RAM. (All this can be useful in operating systems with virtual memory too).

Bye,
bearophile
Dec 02 2008
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 I asked this over on stackoverflow.com to see what people using other 
 languages have to say, as well as the D community. The reason I ask is 
 to see if memory allocation can be allowed in functions marked "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error 
 

shouldn't have happened in the first place. As far as I can tell, the only thing you could do to recover from an out-of-memory condition is (1) to free some memory, or (2) to switch to an algorithm which doesn't need as much memory. Strategy (1): Windows used to have a WM_COMPACTING message (maybe it still does) which was sent when the system was running low on memory. In D, you could imagine a similar sort of system callback, which is called when memory is short -- it means, free some memory now, otherwise you'll get an out of memory error. This is much simpler and more powerful than catching an OutOfMemoryException, freeing some memory, and then repeating what you were doing. Strategy (2): If you've got a second algorithm to use, why weren't you checking available memory, and choosing the correct algorithm in the first place? I don't think either of these strategies make sense. The technique of catching exceptions works because you have locality of reference of almost all resources. If you get a FileException, the bit of code which deals with that particular file is small, and you can unroll the call stack to get past it. But memory usage is a whole-program thing. The biggest unnecessary memory allocation might be a completely unrelated part of the program.
Dec 02 2008
next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Don wrote:
 Strategy (1):
 Windows used to have a WM_COMPACTING message (maybe it still does) which 
 was sent when the system was running low on memory. In D, you could 
 imagine a similar sort of system callback, which is called when memory 
 is short -- it means, free some memory now, otherwise you'll get an out 
 of memory error.
 This is much simpler and more powerful than catching an 
 OutOfMemoryException, freeing some memory, and then repeating what you 
 were doing.

I like
Dec 02 2008
prev sibling next sibling parent Sergey Gromov <snake.scaly gmail.com> writes:
Tue, 02 Dec 2008 14:57:49 +0100, Don wrote:

 Walter Bright wrote:
 I asked this over on stackoverflow.com to see what people using other 
 languages have to say, as well as the D community. The reason I ask is 
 to see if memory allocation can be allowed in functions marked "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error 
 

shouldn't have happened in the first place. As far as I can tell, the only thing you could do to recover from an out-of-memory condition is (1) to free some memory, or (2) to switch to an algorithm which doesn't need as much memory.

or (3) to fail a self-contained, user initiated, "pure" operation. Like image loading process, or an expensive image editing operation, or a complex calculation. You'll find this sort of recovery in any interactive data processing application.
Dec 04 2008
prev sibling parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Don" <nospam nospam.com> wrote in message 
news:gh3et3$13tm$1 digitalmars.com...
 Walter Bright wrote:
 I asked this over on stackoverflow.com to see what people using other 
 languages have to say, as well as the D community. The reason I ask is to 
 see if memory allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

shouldn't have happened in the first place. As far as I can tell, the only thing you could do to recover from an out-of-memory condition is (1) to free some memory, or (2) to switch to an algorithm which doesn't need as much memory. Strategy (1): Windows used to have a WM_COMPACTING message (maybe it still does) which was sent when the system was running low on memory. In D, you could imagine a similar sort of system callback, which is called when memory is short -- it means, free some memory now, otherwise you'll get an out of memory error. This is much simpler and more powerful than catching an OutOfMemoryException, freeing some memory, and then repeating what you were doing.

There ought to be a means of giving the GC a function to call whenever it's about to do its business.
 Strategy (2):
 If you've got a second algorithm to use, why weren't you checking 
 available memory, and choosing the correct algorithm in the first place?

Because there's no documented function in Phobos for checking how much memory is available, possibly? Stewart. -- My e-mail address is valid but not my primary mailbox. Please keep replies on the 'group where everybody may benefit.
Dec 06 2008
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 02 Dec 2008 07:13:12 -0500, Walter Bright  
<newshound1 digitalmars.com> wrote:
 I asked this over on stackoverflow.com to see what people using other  
 languages have to say, as well as the D community. The reason I ask is  
 to see if memory allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

No. An out of memory error from the GC is should not generally be recoverable inside of the current thread. (Recoverable thread (user or kernel) creation and termination should be supported though) Regarding the counter examples: I'm currently working on a D project which uses NVIDIA's CUDA platform for GPU computing. Instead of manually managing GPU memory, I've created proxy objects to leverage the D's GC. So when the GPU returns an out of memory error, I run a full collect and only raise an exception if it fails a second time. But, this isn't really and example of out of memory recovery, and more one of GC integration. The other examples of recovery (caches, free-lists, stacks/hashes without auto-shrinking, etc) are all structures that have their own methods of collecting/compacting memory which are separate from the GC and tend not to be local to the allocating function. So people might implement something like the following: T new2(T)( lazy T old_new ) { T obj; try{ obj = old_new; }catch(OutOfMemoryException oome) { foreach(compact; Global_List_Of_Delegates_From_Compatible_Objects) compact(); obj = old_new; } return obj; } Which is a decent argument for adding support for registering/unregistering self-collecting/compacting objects to the GC.
Dec 02 2008
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
I asked this over on stackoverflow.com to see what people using other 
languages have to say, as well as the D community. The reason I ask is to 
see if memory allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

It can be. For example, if you want to allocate a gigantic buffer to see if you can load a file, you may catch for failure, and display an appropriate message to the user on failure. The application could still continue to run. I think the difference between recoverable and non-recoverable is the size of the allocation. If the size is sufficiently large enough, you can still have memory to deal with the failure. If allocating 16 bytes gives you a failure, then may not be able to do much to get around it. In most cases, an out of memory failure is a non-recoverable error. My thoughts are, add a recoverable allocate function to the GC. If one wants a recoverable memory error, he must call that function to allocate. Don't allow that function in nothrow functions, but allow standard (non recoverable) memory allocation to be called. -Steve
Dec 02 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 It can be.  For example, if you want to allocate a gigantic buffer to see if 
 you can load a file, you may catch for failure, and display an appropriate 
 message to the user on failure.  The application could still continue to 
 run.  I think the difference between recoverable and non-recoverable is the 
 size of the allocation.  If the size is sufficiently large enough, you can 
 still have memory to deal with the failure.  If allocating 16 bytes gives 
 you a failure, then may not be able to do much to get around it.

I should point out that in such cases (probing a large allocation), the error recovery is very local. I.e. there's no need for throwing an exception and then recovering in some arbitrary user code way up the stack.
 In most cases, an out of memory failure is a non-recoverable error.  My 
 thoughts are, add a recoverable allocate function to the GC.  If one wants a 
 recoverable memory error, he must call that function to allocate.  Don't 
 allow that function in nothrow functions, but allow standard (non 
 recoverable) memory allocation to be called.

I think this may be the best strategy.
Dec 02 2008
prev sibling next sibling parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 I asked this over on stackoverflow.com to see what people using other 
 languages have to say, as well as the D community. The reason I ask is 
 to see if memory allocation can be allowed in functions marked "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error 

It seems that D has (or rather, can have) a trivial solution to this problem. Allow programs to register with the GC when they have memory which can be easily freed (caches and such). Then you can make "out of memory" a non-recoverable error, since it only hits when we fail to recover enough. It seems to me that there are 3 different types of callbacks that can be registered: pre-scan, post-scan, and crisis. PRE-SCAN Before the mark & sweep runs, *every one* of these callbacks is called. These are for things which the program can give up with very little cost, such as emptying free pools in allocators. Since this happens before the scan, you do *not* have to use explicit "delete"s; you can just drop references as normal. After all of these callbacks are called, the mark & sweep runs, and we hope that it will find some newly-discarded regions. POST-SCAN This is for things which we typically don't want to give up, but which we might relinquish if the only alternative would be getting more memory from the OS. For instance, caches of things read from disk. In this case, callbacks must explicitly delete things (since the scanner has already run). The GC will call each of these in turn, but will stop if and when enough (contiguous) memory is freed to perform the allocation that the GC is trying to perform. If the GC goes through the entire list without finding enough, it will ask the OS for more memory. CRISIS This is a set of callbacks which represent things which we would only discard in a true crisis, such as caches which would be time-consuming to rebuild. These are called only if the OS refuses to give us more memory. Again, you have to explicitly delete, and the GC will stop calling if and when it finds enough free memory. Seems to me that with this mechanism in place, we can treat out-of-memory as an unrecoverable error. Thoughts? P.S. It would be nice to also have callbacks that were called when the OS started page swapping, or callbacks to deal with fragmentation. But that is something to consider some other time...
Dec 02 2008
next sibling parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Tue, Dec 2, 2008 at 11:57 AM, Russell Lewis
<webmaster villagersonline.com> wrote:
 It seems that D has (or rather, can have) a trivial solution to this
 problem.  Allow programs to register with the GC when they have memory which
 can be easily freed (caches and such).  Then you can make "out of memory" a
 non-recoverable error, since it only hits when we fail to recover enough.

 ...

 Thoughts?

I've considered this as well. I've had a few occasions where I really wanted something to trigger upon garbage collection. Conveniently, this is also dead easy to implement.
Dec 02 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 On Tue, Dec 2, 2008 at 11:57 AM, Russell Lewis
 <webmaster villagersonline.com> wrote:
 It seems that D has (or rather, can have) a trivial solution to this
 problem.  Allow programs to register with the GC when they have memory which
 can be easily freed (caches and such).  Then you can make "out of memory" a
 non-recoverable error, since it only hits when we fail to recover enough.

 ...

 Thoughts?

I've considered this as well. I've had a few occasions where I really wanted something to trigger upon garbage collection. Conveniently, this is also dead easy to implement.

I think some gc schemes implement this.
Dec 02 2008
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Russell Lewis (webmaster villagersonline.com)'s article
 Walter Bright wrote:
 I asked this over on stackoverflow.com to see what people using other
 languages have to say, as well as the D community. The reason I ask is
 to see if memory allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

problem. Allow programs to register with the GC when they have memory which can be easily freed (caches and such). Then you can make "out of memory" a non-recoverable error, since it only hits when we fail to recover enough.

Interesting idea. It would certainly be easy enough to add to the GC. Sean
Dec 02 2008
prev sibling next sibling parent BCS <ao pathlink.com> writes:
Reply to Russell,

 Walter Bright wrote:
 
 I asked this over on stackoverflow.com to see what people using other
 languages have to say, as well as the D community. The reason I ask
 is to see if memory allocation can be allowed in functions marked
 "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recovera
 ble-error
 

problem. Allow programs to register with the GC when they have memory which can be easily freed (caches and such). Then you can make "out of memory" a non-recoverable error, since it only hits when we fail to recover enough.

Some sort of higher level of granularity would be nice, mostly an ordering hint re the different stages.
 
 Seems to me that with this mechanism in place, we can treat
 out-of-memory as an unrecoverable error.
 
 Thoughts?

vote += 0.5; // nice idea, not sure it would help *me* in any way though.
Dec 02 2008
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
Russell Lewis, el  2 de diciembre a las 09:57 me escribiste:
 PRE-SCAN
 
 Before the mark & sweep runs, *every one* of these callbacks is called.
 These are for things which the program can give up with very little
 cost, such as emptying free pools in allocators.  Since this happens
 before the scan, you do *not* have to use explicit "delete"s; you can
 just drop references as normal.  After all of these callbacks are
 called, the mark & sweep runs, and we hope that it will find some
 newly-discarded regions.

I think one could benefit from manually deleting stuff, if possible. This way, space can be found before the collection, and you saved yourself some collecting time. Manually deleting stuff could remain optional, no problem with that, so if you have data that it's not that trivial to decide if it's unused, you can just leave that work to the collector.
 Thoughts?

Looks really interesting. This could be a perfect complement to a way to ask for memory when you expect the memory allocation to fail. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- People love to judge homeless guys. Like, your giving him money he's just gonna waste it. He's just gonna waste the money Well, he lives in a box, what do you want him to do? Save up and buy a wall unit? Take a little run to the store for a throw rug and a CD rack? He's homeless.
Dec 03 2008
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 I asked this over on stackoverflow.com to see what people using other
 languages have to say, as well as the D community. The reason I ask is
 to see if memory allocation can be allowed in functions marked "nothrow".
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

Yes, but unlike some exceptions where retrying the same code may succeed, an out of memory condition almost always requires explicit handling for recovery. Because it's not typical for an application to explicitly handle memory errors however, I think an OOME can generally be treated as an unrecoverable error. I suppose it's worth mentioning that the OOME exception class derives from Error now in D 2.0, for the reasons mentioned above. Not sure if you'd simply like to judge recoverability based on the superclass choice, but it would be a simple enough rule to follow. Sean
Dec 02 2008
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
One can get rid of OOM just by adding a couple of lines to the default malloc,
that call custom handler (similar to onOutOfMemoryError handler) wich does any
magic wanted, so OOM doesn't break nothrow functions, and if it's thrown, this
means that recovery code has failed to recover and application exits. So
nothrow protocol remains the same.
Dec 02 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Kagamin (spam here.lot)'s article
 One can get rid of OOM just by adding a couple of lines to the default malloc,
that call custom handler

Endless loop. Sean
Dec 02 2008
prev sibling parent Kagamin <spam here.lot> writes:
Kagamin Wrote:

 One can get rid of OOM just by adding a couple of lines to the default malloc,
that call custom handler (similar to onOutOfMemoryError handler) wich does any
magic wanted, so OOM doesn't break nothrow functions, and if it's thrown, this
means that recovery code has failed to recover and application exits. So
nothrow protocol remains the same.

I think, preventing OOM is the only possible technique to make sure you don't interfere with the rest of the application.
Dec 02 2008
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:gh38om$m7r$1 digitalmars.com...
I asked this over on stackoverflow.com to see what people using other 
languages have to say, as well as the D community. The reason I ask is to 
see if memory allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

I haven't looked at any of the other responses yet, but I'd have to say "sometimes". Clearly, getting an out of memory when trying to instantiate a trivial class is nonrecoverable (unless it's happening within a section of memory-intensive code that's allowed to fail, and the rest of the program does very little allocation), but getting an out of memory when trying to allocate a 1GB buffer for video processing is certainly recoverable.
Dec 03 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 I haven't looked at any of the other responses yet, but I'd have to say 
 "sometimes". Clearly, getting an out of memory when trying to instantiate a 
 trivial class is nonrecoverable (unless it's happening within a section of 
 memory-intensive code that's allowed to fail, and the rest of the program 
 does very little allocation), but getting an out of memory when trying to 
 allocate a 1GB buffer for video processing is certainly recoverable. 

There aren't going to be very many instances in code where one allocates 1Gb, so those can be handled as special cases.
Dec 04 2008
prev sibling next sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el  2 de diciembre a las 04:13 me escribiste:
 I asked this over on stackoverflow.com to see what people using other
languages 
 have to say, as well as the D community. The reason I ask is to see if memory 
 allocation can be allowed in functions marked "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

I think all the things said in this thread makes sense (adding callbacks to the garbage collector, adding a way to ask for memory that don't throw if the memory can't be allocated), but I think this don't cover all the possible scenarios. For example, I'm working on a softswitch (unfortunately no in D). Lets say we have a really bad moment and all the subscribers want to talk at the same time and we don't support that workload. Lets say our memory is exhausted and a new call arrive. A new allocation is done somewhere deep inside the call logic, so the PRE COLLECT callback is called. No memory can be reclaimed, so the GC runs a collection. Still no memory. POST COLLECT and CRISIS are called too without success. My softswitch is down, I lost all the current calls. This is not good for business. What I really wanted to do is to catch the memory error as shallow in the call logic as possible and drop only that current call, leaving all the current established calls intact. So what can I do? Should I manually check each and every allocation in all the call logic? I think that's unacceptable. I think this scenario apply to each client-server application that needs to stay alive even with high workloads, as the expense of dropping some connection/client (web servers or web applications for example, as someone said in stackoverflow.com). -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- PADRES DENUNCIAN QUE SU HIJA SE ESCAPO CON UN PARAGUAYITO -- Crónica TV
Dec 03 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Leandro Lucarella (llucax gmail.com)'s article
 Walter Bright, el  2 de diciembre a las 04:13 me escribiste:
 I asked this over on stackoverflow.com to see what people using other languages
 have to say, as well as the D community. The reason I ask is to see if memory
 allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

to the garbage collector, adding a way to ask for memory that don't throw if the memory can't be allocated), but I think this don't cover all the possible scenarios. For example, I'm working on a softswitch (unfortunately no in D). Lets say we have a really bad moment and all the subscribers want to talk at the same time and we don't support that workload. Lets say our memory is exhausted and a new call arrive. A new allocation is done somewhere deep inside the call logic, so the PRE COLLECT callback is called. No memory can be reclaimed, so the GC runs a collection. Still no memory. POST COLLECT and CRISIS are called too without success. My softswitch is down, I lost all the current calls. This is not good for business. What I really wanted to do is to catch the memory error as shallow in the call logic as possible and drop only that current call, leaving all the current established calls intact.

The same could be said of any unexpected error in such an application. Assuming that you're doing call processing in a multithreaded app as opposed to dedicating a process per call (as in Erlang) then you'll have to use try/catch blocks carefully to perform the necessary cleanup at each stage, re-throwing exceptions you don't intend to handle.
 So what can I do? Should I manually check each and every allocation in all
 the call logic? I think that's unacceptable.

Agreed. The point of exceptions is to avoid the need to verify the result of every operation and to avoid duplication of recovery code. Sean
Dec 03 2008
prev sibling next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Robert Jacques wrote:
 2) One can still catch an error if need be.

Not if the function is nothrow, since the function never sets up an exception handling frame (that's the point of this topic, AFAICT).
Dec 03 2008
next sibling parent KennyTM~ <kennytm gmail.com> writes:
Robert Fraser wrote:
 Robert Jacques wrote:
 2) One can still catch an error if need be.

Not if the function is nothrow, since the function never sets up an exception handling frame (that's the point of this topic, AFAICT).

Make a non-recoverable version as standard, and a recoverable version that throws an Exception/return null as a last-resort if you really want to handle the mess (free other memories).
Dec 04 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Robert Fraser wrote:
 Robert Jacques wrote:
 2) One can still catch an error if need be.

Not if the function is nothrow, since the function never sets up an exception handling frame (that's the point of this topic, AFAICT).

Not exactly. If you set up a try-catch, an exception handling frame is set up. An exception handling frame is not necessary in order to throw an exception, it is only necessary to: 1. catch exceptions 2. unwind exceptions (run destructors) What happens if a nothrow function does throw is that your destructors and finally clauses may not get run in between the throw and the catch. For example: nothrow void foo(); void bar() { try { foo(); } finally { will_never_execute(); // even if foo() throws } } because the compiler will optimize away the finally clause.
Dec 04 2008
parent reply Christopher Wright <dhasenan gmail.com> writes:
Walter Bright wrote:
 nothrow void foo();
 
 void bar()
 {
     try
     {
     foo();
     }
     finally
     {
         will_never_execute(); // even if foo() throws
     }
 }
 
 because the compiler will optimize away the finally clause.

! ! ! Surely you mean "catch" rather than "finally"? I should hope that the code you have there is equivalent to: void bar() { foo(); will_never_execute(); } Otherwise you'd break calling code by switching a function to nothrow.
Dec 04 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Christopher Wright wrote:
 Walter Bright wrote:
 nothrow void foo();

 void bar()
 {
     try
     {
     foo();
     }
     finally
     {
         will_never_execute(); // even if foo() throws
     }
 }

 because the compiler will optimize away the finally clause.

! ! ! Surely you mean "catch" rather than "finally"?

Yes. Oops!!!
Dec 05 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Robert Jacques wrote:
 Okay, while we've been talking about OutOfMemoryError there's also 
 RangeError, AssertError, FinalizeError and SwitchError and not allowing 
 array indexing, contract programming or switches inside a nothrow 
 function drastically reduces their usefulness (more so than allocation, 
 in my opinion). So at least in debug mode, the handling frame (I think) 
 exists in order to support RangeError and AssertError errors. However, 
 SwitchError and HiddenFuncError occur in release code, so I'm not sure 
 if nothrow functions will not have some error handling method. (I think 
 FinalizeError is related to allocation and therefore OutOfMemoryError)

The idea behind Errors is that, even if you catch the exception, unwinding may not occur. Thus, your app should not be relying on destructors cleaning up properly. Catching an Error should only be used for doing things necessary before shutting down the app.
Dec 04 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Robert Jacques wrote:
 Okay, while we've been talking about OutOfMemoryError there's also
 RangeError, AssertError, FinalizeError and SwitchError and not allowing
 array indexing, contract programming or switches inside a nothrow
 function drastically reduces their usefulness (more so than allocation,
 in my opinion). So at least in debug mode, the handling frame (I think)
 exists in order to support RangeError and AssertError errors. However,
 SwitchError and HiddenFuncError occur in release code, so I'm not sure
 if nothrow functions will not have some error handling method. (I think
 FinalizeError is related to allocation and therefore OutOfMemoryError)

unwinding may not occur. Thus, your app should not be relying on destructors cleaning up properly. Catching an Error should only be used for doing things necessary before shutting down the app.

I disagree. D is a systems app and so should not require termination on any error. The distinction to me is that Errors require special handling if recovery is to be attempted, while it's often safe (if bad practice) to simply log Exceptions and soldier on. That isn't to say that it's always possible (and certainly not always advisable) to recover from an Error, but I think that decision should be left up to the user. Sean
Dec 04 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 I disagree.  D is a systems app and so should not require termination on
 any error.  The distinction to me is that Errors require special handling
 if recovery is to be attempted, while it's often safe (if bad practice) to
 simply log Exceptions and soldier on.  That isn't to say that it's always
 possible (and certainly not always advisable) to recover from an Error,
 but I think that decision should be left up to the user.

If we go down that path, then nothrow functions can never allocate memory.
Dec 05 2008
parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el  5 de diciembre a las 15:05 me escribiste:
 Sean Kelly wrote:
I disagree.  D is a systems app and so should not require termination on
any error.  The distinction to me is that Errors require special handling
if recovery is to be attempted, while it's often safe (if bad practice) to
simply log Exceptions and soldier on.  That isn't to say that it's always
possible (and certainly not always advisable) to recover from an Error,
but I think that decision should be left up to the user.

If we go down that path, then nothrow functions can never allocate memory.

Maybe they shouldn't (and if this is true, maybe there is too little use for nothrow :S) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Software is like sex: it's better when it's free. -- Linus Torvalds
Dec 05 2008
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Robert Jacques, el  3 de diciembre a las 09:39 me escribiste:
 That's a good point/use case. However,
 1) Many client-sever applications seperate each client into a logical thread
of 
 some kind. And inside this thread, out of memory is not recoverable.

Unfortunatelly not all designs are multithread. In my for example, we work with a single thread event loop.
 2) One can still catch an error if need be.

I don't know what do you mean by that. If you mean you could use a try/catch block, that's no true if allocation can't throw (to be able to allocate in nothrow functions). If you mean you can use an allocation function that don't throw but report the failure in other way (like returning a null pointer), yes, as I said one, could always use that function, but is a PITA (specially for string manipulation, hashes and dynamic arrays). -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- La terapia no sirve: es mucho mejor pagar para hacer las perversiones que para contarlas. -- Alberto Giordano (filósofo estilista)
Dec 04 2008
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Leandro Lucarella wrote:
 For example, I'm working on a softswitch (unfortunately no in D). Lets say
 we have a really bad moment and all the subscribers want to talk at the
 same time and we don't support that workload. Lets say our memory is
 exhausted and a new call arrive. A new allocation is done somewhere deep
 inside the call logic, so the PRE COLLECT callback is called. No memory
 can be reclaimed, so the GC runs a collection. Still no memory. POST
 COLLECT and CRISIS are called too without success. My softswitch is down,
 I lost all the current calls. This is not good for business. What I really
 wanted to do is to catch the memory error as shallow in the call logic as
 possible and drop only that current call, leaving all the current
 established calls intact.
 
 So what can I do? Should I manually check each and every allocation in all
 the call logic? I think that's unacceptable.

That's a very good point. I need to think about that one.
Dec 04 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Leandro Lucarella wrote:
 For example, I'm working on a softswitch (unfortunately no in D). Lets say
 we have a really bad moment and all the subscribers want to talk at the
 same time and we don't support that workload. Lets say our memory is
 exhausted and a new call arrive. A new allocation is done somewhere deep
 inside the call logic, so the PRE COLLECT callback is called. No memory
 can be reclaimed, so the GC runs a collection. Still no memory. POST
 COLLECT and CRISIS are called too without success. My softswitch is down,
 I lost all the current calls. This is not good for business. What I really
 wanted to do is to catch the memory error as shallow in the call logic as
 possible and drop only that current call, leaving all the current
 established calls intact.
 
 So what can I do? Should I manually check each and every allocation in all
 the call logic? I think that's unacceptable.
 
 I think this scenario apply to each client-server application that needs
 to stay alive even with high workloads, as the expense of dropping some
 connection/client (web servers or web applications for example, as someone
 said in stackoverflow.com).

Ok, I thought about this for a while. When a virtual memory system gets close to running out of memory, it slows to a crawl and starts thrashing the disk. Other processes on the computer also start to fail by running out of memory. The program will continue to function, but it will function so poorly it might as well have aborted. The solution is to calculate (or measure) the average memory consumption of each call. Determine the maximum memory the software should reasonably consume without thrashing, divide by the memory consumption per call, and that gives a max number of simultaneous calls. Drop calls that exceed that. This scheme should work better, and still provides some slack if the calls dramatically exceed their average memory consumption.
Dec 05 2008
parent reply Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el  5 de diciembre a las 15:04 me escribiste:
 Leandro Lucarella wrote:
For example, I'm working on a softswitch (unfortunately no in D). Lets say
we have a really bad moment and all the subscribers want to talk at the
same time and we don't support that workload. Lets say our memory is
exhausted and a new call arrive. A new allocation is done somewhere deep
inside the call logic, so the PRE COLLECT callback is called. No memory
can be reclaimed, so the GC runs a collection. Still no memory. POST
COLLECT and CRISIS are called too without success. My softswitch is down,
I lost all the current calls. This is not good for business. What I really
wanted to do is to catch the memory error as shallow in the call logic as
possible and drop only that current call, leaving all the current
established calls intact.
So what can I do? Should I manually check each and every allocation in all
the call logic? I think that's unacceptable.
I think this scenario apply to each client-server application that needs
to stay alive even with high workloads, as the expense of dropping some
connection/client (web servers or web applications for example, as someone
said in stackoverflow.com).

Ok, I thought about this for a while. When a virtual memory system gets close to running out of memory, it slows to a crawl and starts thrashing the disk. Other processes on the computer also start to fail by running out of memory. The program will continue to function, but it will function so poorly it might as well have aborted. The solution is to calculate (or measure) the average memory consumption of each call. Determine the maximum memory the software should reasonably consume without thrashing, divide by the memory consumption per call, and that gives a max number of simultaneous calls. Drop calls that exceed that. This scheme should work better, and still provides some slack if the calls dramatically exceed their average memory consumption.

This is not still the only possible case. See this: luca homero:/tmp$ cat mem.d import core.stdc.stdio: printf; import core.exception: OutOfMemoryError; void main() { try { auto x = new char[1_000_000]; } catch (OutOfMemoryError e) { printf("woops! no more memory\n"); } } luca homero:/tmp$ ulimit -v 3000 luca homero:/tmp$ dmd mem.d luca homero:/tmp$ ./mem woops! no more memory I swear my system didn't trash! =) This is not some stupid thing just to prove you wrong. When I want my process to live for as long as possible, even in extreme situations like lack of memory, it's a very good option to do this. Because of the reasons you gave about trashing. Its more desirable that my softswitch start dropping calls a little earlier than necessary but can maintain the current ones smoothly, than let the system trash and hope for the best. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- DETIENEN A PADRE, MADRE, TIOS Y ABUELOS: TODOS DEPRAVADOS -- Crónica TV
Dec 06 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Leandro Lucarella wrote:
 I swear my system didn't trash! =)
 
 This is not some stupid thing just to prove you wrong. When I want my
 process to live for as long as possible, even in extreme situations like
 lack of memory, it's a very good option to do this. Because of the reasons
 you gave about trashing. Its more desirable that my softswitch start
 dropping calls a little earlier than necessary but can maintain the
 current ones smoothly, than let the system trash and hope for the best.

I think you meant thrash, not trash!
Dec 08 2008
parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el  8 de diciembre a las 17:35 me escribiste:
 Leandro Lucarella wrote:
I swear my system didn't trash! =)
This is not some stupid thing just to prove you wrong. When I want my
process to live for as long as possible, even in extreme situations like
lack of memory, it's a very good option to do this. Because of the reasons
you gave about trashing. Its more desirable that my softswitch start
dropping calls a little earlier than necessary but can maintain the
current ones smoothly, than let the system trash and hope for the best.

I think you meant thrash, not trash!

Yes, of course =) (I'm not a native english speaker, so excuse me for this error, and that will come in the future ;) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- "Lidiar" no es lo mismo que "holguear"; ya que "lidiar" es relativo a "lidia" y "holguear" es relativo a "olga". -- Ricardo Vaporeso
Dec 09 2008
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Wed, 03 Dec 2008 08:34:43 -0500, Leandro Lucarella <llucax gmail.com>  
wrote:

 Walter Bright, el  2 de diciembre a las 04:13 me escribiste:
 I asked this over on stackoverflow.com to see what people using other  
 languages
 have to say, as well as the D community. The reason I ask is to see if  
 memory
 allocation can be allowed in functions marked "nothrow".

 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

I think all the things said in this thread makes sense (adding callbacks to the garbage collector, adding a way to ask for memory that don't throw if the memory can't be allocated), but I think this don't cover all the possible scenarios. For example, I'm working on a softswitch (unfortunately no in D). Lets say we have a really bad moment and all the subscribers want to talk at the same time and we don't support that workload. Lets say our memory is exhausted and a new call arrive. A new allocation is done somewhere deep inside the call logic, so the PRE COLLECT callback is called. No memory can be reclaimed, so the GC runs a collection. Still no memory. POST COLLECT and CRISIS are called too without success. My softswitch is down, I lost all the current calls. This is not good for business. What I really wanted to do is to catch the memory error as shallow in the call logic as possible and drop only that current call, leaving all the current established calls intact. So what can I do? Should I manually check each and every allocation in all the call logic? I think that's unacceptable. I think this scenario apply to each client-server application that needs to stay alive even with high workloads, as the expense of dropping some connection/client (web servers or web applications for example, as someone said in stackoverflow.com).

That's a good point/use case. However, 1) Many client-sever applications seperate each client into a logical thread of some kind. And inside this thread, out of memory is not recoverable. 2) One can still catch an error if need be.
Dec 03 2008
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Wed, 03 Dec 2008 14:47:14 -0500, Robert Fraser  
<fraserofthenight gmail.com> wrote:
 Robert Jacques wrote:
 2) One can still catch an error if need be.


Yeah, I'm not sure what I was thinking here.
 Not if the function is nothrow, since the function  never sets up an  
 exception handling frame (that's the point of this topic, AFAICT).

Okay, while we've been talking about OutOfMemoryError there's also RangeError, AssertError, FinalizeError and SwitchError and not allowing array indexing, contract programming or switches inside a nothrow function drastically reduces their usefulness (more so than allocation, in my opinion). So at least in debug mode, the handling frame (I think) exists in order to support RangeError and AssertError errors. However, SwitchError and HiddenFuncError occur in release code, so I'm not sure if nothrow functions will not have some error handling method. (I think FinalizeError is related to allocation and therefore OutOfMemoryError) PS. I would class removing the exception handling frame as an optimization which is separate from the nothrow language contract feature.
Dec 03 2008
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-12-02 07:13:12 -0500, Walter Bright <newshound1 digitalmars.com> said:

 I asked this over on stackoverflow.com to see what people using other 
 languages have to say, as well as the D community. The reason I ask is 
 to see if memory allocation can be allowed in functions marked 
 "nothrow".
 
 http://stackoverflow.com/questions/333736/is-out-of-memory-a-recoverable-error

I think you got the question wrong. My answer would be: it depends. I think you could make this simple reasonable rule: anything that would throw an exception in a nothrow function yeilds a fatal error. When you want to catch out of memory errors (or any other error for that matter), just avoid nothrow. How does that sound? It sounds to me like nothrow functions are going to be dangerous in big applications since it could make some distant part of an app crash the whole thing. At least, you should be allowed to handle those exceptions (out of memory, range error, etc) in an error handler function before it kills the current thread. But even with that it'll be hard to guarenty proper cleanup; that's why I'm saying it makes nothrow dangerous. Note however that you can't guarenty proper cleanup either in case of division by zero or invalid pointer dereferencing, so by allowing dynamic allocation you're not extending the problem very much. It'd be great if those could throw exceptions when not in a nothrow function. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2008
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2008-12-04 07:34:18 -0500, Michel Fortin <michel.fortin michelf.com> said:

 I think you got the question wrong. My answer would be: it depends.

I forgot to rephase explicitly the question. What I'm answering in the parent post is: "When should an out of memory exception be a fatal error?" And the answer I give in the parent post would be: "When you're in a nothrow function!" -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2008