There is a way of which (to my knowledge) is not implemented in any technology.
Presuming you know how the maybe monad (or similar named monads) handles errors. A MaybeOutOfMemoryError works in a similar way in the sense that any attempt to use the value meaningfully will force you to handle the error.
data MaybeOutOfMemoryError a = OutOfMemoryError | Some a
ioFunction :: MaybeOutOfMemoryError a -> IO
ioFunction OutOfMemoryError = println "ERROR"
ioFunction Some _ = println "No ERROR"
exhaustive pattern matching with the error flag enabled makes it so that if you forget the OutOfMemoryError case an error will occur during compile time.
Any function that can potentially trigger a memory error should be forced to be typed like this. However in programming, ALL functions can potentially do this, and side effects outside of the scope of the function (total memory available) will trigger it meaning that the only way to do this effectively is to make ALL functions typed this way. Which is inconvenient to say the least.
That being said you can just type the main function as something that can only accept this monadic value forcing users to wrap this handling in a top level function:
myWrittenProgram :: MaybeOutOfMemoryError a
-- not defined in this example
-- main is forced to be typed this way just like how in haskell it is forced to be typed IO ()
main :: MaybeOutOfMemoryError a -> IO ()
main Some a = printLn a
main OutOfMemoryError = printLn "Error out of memory"
Obviously the above has some issues with the rest of haskell syntax and the way things are done, but I'm just showing you a way where it is possible to make sure that a memory runtime error does not happen (that is an unhandled runtime error).
That being said unless you know haskell or know what a maybe monad is, you wouldn't be able to fully comprehend what I said. Exception monads exist in haskell, but nothing is forcing the main function to be typed this way.