FUTURE POSTS
- Partial writes, IO_Uring and safety - one day from now
- Configuration values & Escape hatches - 4 days from now
- What happens when a sparse file allocation fails? - 6 days from now
- NTFS has an emergency stash of disk space - 8 days from now
- Challenge: Giving file system developer ulcer - 11 days from now
And 4 more posts are pending...
There are posts all the way to Feb 17, 2025
Comments
There is not enough memory for creating a new OutOfMemoryException
Missing semicolon?
I think, you swallow the exception
Do this :
throw outOfMemoryError(ex.message, ex.InnerException)
you should just do throw rather than a new exception. if you throw new exception the "real" exception will be hidden inside inner exception and you need to loop through inner exception to find the "real" exception.
This is a classic example of why you shouldn't do
catch (Exception e)
{
...
}
Only this is more obvious.
Don't think you can catch OutOfMemoryException.
Depending on the hosting environment critical exception can cause a rude AppDomain unload. Your handler might not be executing et all.
I'm with Oded on this. how can you create a new exception to bubble up if you are out of memory.
This makes one wonder how the original OutOfMemoryException can be created and thrown in the first place.
OOM, like ExecutionEngineException and one other, are always on the heap because you can't guarantee during an OOM that you'll be able to create an object on the heap. You can see that by attaching with WinDBG and doing a "!dumpheap -type Exception".
For those wondering, you can absolutely catch OutOfMemoryExceptions. As noted here: stackoverflow.com/.../when-is-it-ok-to-catch-an... you may have an image editing application which is allocating a buffer. You need to be able to handle that condition. It's not fatal, unless it bubbles up. Or unless you were trying to autobox a variable and couldn't get even 12 bytes of memory.
I'm assuming that the screenshot cut off where you wrap the original OOM exception. Generally you don't throw a new exception, since you lose the stack trace, but I can't see the constructor to tell what you are doing there - so I'll assume you're doing the right thing. ;)
Something else to note - if your OOM exception path calls methods that may not have been JIT'd, then you can get even more fun because there isn't enough memory to store the compiled code in the metadata, nor update the pointers to it. This can result it even more OOM exceptions, and the framework can do all kinds of interesting things to make sure at least one OOM gets bubbled up.
Don't you want to release the resources that were being used that cause the OOM exception before throwing another exception?
not that it much matters, but as a point to some previous comments, as Cory mentions, someone could attempt to allocate something huge (say, 3GB on a 32-bit machine with the default 2/2 split) and that hits the OOM, but there may still be plenty of free memory that's sufficient for creating things like, say, an OOM exception.
Also, keep in mind that a lot of things in the 'try' block (not to mention potentially other things) may have just gone out of scope (lost their root reference path) so they may be free to get GC'd as part of the new OOM allocation if necessary.
Based on the comment it seems like you want to wrap the original OOM to get a new message. I've never tried it, but I wonder if you could just modify e.Message and then throw; to preserve the original stack without creating the outer wrapper.
Of course, since you mention the hint is for 32-bit users, it'd be potentially nice to wrap the 'hint' in an if IntPtr.Size == 4 and have the else case just throw; since there's no point in providing that hint to your 64-bit users :)
I have to admit I'm a little surprised that there hasn't been at least one comment of someone proposing trying to 'help' the memory situation manually (like WaitForPendingFinalizers and potentially doing a manual GC.Collect) before trying an allocation (even if just an OOM wrapper exception).
a) Swallows original exception, so no context propagated
b) Will there even be any memory to create the OOME ?
@Joseph: This is .NET, so there is no "release" concept. Not that would help you much here. You could theoretically set an object instance to null, and then manually call GC.Collect, but unless you were explicitly trying to allocate a specific block of memory and are trying to recover from a specific and well-tested block of code, anything "helpful" is likely just going to delay the problem and make debugging it even worse. The GC and memory manager have been written by some quite bright people, and while there are rare cases where you may know more than the Memory Manager, they are few and far between.
@manningj - That no one suggested that is either a sign of people knowing enough not to try that in a general case, or people not understanding enough about the framework to know what WaitForPendingFinalizers does, or even what really goes on during a GC. I'm hoping it's the former. ;)
@Cory, Normally I would have to agree, but If the resources are long lasting connections to sockets or the resources are into un-managed code you would, I believe, want to release them. Maybe even clean up some dangling delegates. Specifically, concerning bright people, there are constraints, limits, and contexts in which software will not perform as expected otherwise we wouldn't have exceptions ;)
I think the throwing of the of the second OOM after catching the first was for 32bit VM. A good disussion for this is here:
msdn.microsoft.com/en-us/magazine/cc163528.aspx#S8
Specifically, Determining What Caused an OOM Exception.
I'm confused. Why are you attempting to allocate an exception of the same type as what was caught? What additional information is being added? Even if you can allocate a new OutOfMemoryException object, what is gained over simply not catching the exception at all? I'm guessing the comment explains why, but I'm not following the reason?
For one thing, this code doesn't actually handle the exception. If you don't intend to handle the exception meaningfully, there is no reason to catch it in the first place.
Second, by throwing a new exception, you lose the original stack trace. From this point forward, an examination of the stack trace will make it appear as though this is where the error originated. At the very least, the new exception should include the original one in its InnerException property. Of course, you should take the opportunity to add more information at this point; otherwise, as mentioned, there's no point in having the catch at all.
@wcoenen
I'm pretty sure the original OOM exception is pre-allocated by the CLR. I remember talking to someone on the CLR test team when they found this bug.
new System.OutOfMemoryException();
notice the ();
So Ayende, you throw a topic in the air and just leave it here? You teaser.
Bunter,
Oded gave the right answer right away...
Wow, that one was to easy...took me seconds. Your losing your touch ;)
Comment preview