Search code examples
rustruntime-errorallocation

Why doesn't `Box::new` return an `Option` or `Result`?


I don't understand why Box::new doesn't return an Option or Result.

The allocation can fail because memory is not unlimited, or something else could happen; what is the behavior in such cases? I can't find any information about it.


Solution

  • A more general form is What to do on Out Of Memory (OOM)?

    There are many difficulties in handling OOM:

    • detecting it,
    • recovering from it (gracefully),
    • integrating it in the language (gracefully).

    The first issue is detecting it. Many OSes today will, by default, use swap space. In this case, your process is actually in trouble way before you get to the OOM situation because starting to use swap space will significantly slow down the process. Other OSes will kill low-priority processes when a higher process requires more memory (OOM killer), or promise more memory than they currently have in the hope it will not be used or will be available by the time it is necessary (overcommit), etc...

    The second issue is recovering. At the process level, the only way to recover is to free memory... without allocating any in the mean time. This is not as easy as it sounds, for example there is no guarantee that panicking and unwinding will not require allocating memory (for example, the act of storing a panic message could allocate if done carelessly). This is why the current rustc runtime aborts by default on OOM.

    The third issue is language integration: memory allocations are everywhere. Any use of Box, Vec, String, etc... So, if you shun the panic route and use the Result route instead, you need to tweak nearly any mutating method signature to account for this kind of failure, and this will bubble in all interfaces.

    Finally, it's notable that in domains where memory allocation failure need be handled... often times memory allocation is not allowed to start with. In critical embedded software, for example, all memory is allocated up-front and there is a proof that no more than what is allocated will be required.

    This is important, because it means that there are very few situations where (1) dynamic memory allocation is allowed and (2) its failure must be handled gracefully by the process itself.

    And at this point, one can only wonder how much complexity budget should be spent on this, and how much complexity this will push unto the 99% of programs which do not care.