Resource management (computing)

by using features exposed by programming languages (Elder, Jackson & Liblit (2008) is a survey article contrasting different approaches), or may elect to manage them by a host – an operating system or virtual machine – or another program.

Resource management seeks to control access in order to prevent both of these situations.

This is also known as execute around[1] or a code sandwich, and occurs in various other contexts,[2] such as a temporary change of program state, or tracing entry and exit into a subroutine.

The consequences of such an incorrect release range from being silently ignored to crashing the program or unpredictable behavior.

Further, the consequences may not be serious, as the program may already be crashing due to failure to acquire an essential resource.

In computer science, resource contention refers to a conflict that arises when multiple entities attempt to access a shared resource, like random access memory, disk storage, cache memory, internal buses, or external network devices.

The basic approach to resource management is to acquire a resource, do something with it, then release it, yielding code of the form (illustrated with opening a file in Python): This is correct if the intervening ... code does not contain an early exit (return), the language does not have exceptions, and open is guaranteed to succeed.

The resource leak can be resolved in languages that support a finally construction (like Python) by placing the body in a try clause, and the release in a finally clause: This ensures correct release even if there is a return within the body or an exception thrown.

Further, note that the acquisition occurs before the try clause, ensuring that the finally clause is only executed if the open code succeeds (without throwing an exception), assuming that "no exception" means "success" (as is the case for open in Python).

In many languages there are mechanisms that provide encapsulation, such as the with statement in Python: The above techniques – unwind protection (finally) and some form of encapsulation – are the most common approach to resource management, found in various forms in C#, Common Lisp, Java, Python, Ruby, Scheme, and Smalltalk,[1] among others; they date to the late 1970s in the NIL dialect of Lisp; see Exception handling § History.

This works for stack-managed resources, and is implemented in many languages, including C#, Common Lisp, Java, Python, Ruby, and Scheme.

These can be remedied either functionally, by using closures/callbacks/coroutines (Common Lisp, Ruby, Scheme), or by using an object that handles both the acquisition and release, and adding a language construct to call these methods when control enters and exits a scope (C# using, Java try-with-resources, Python with); see below.

An alternative, more imperative approach, is to write asynchronous code in direct style: acquire a resource, and then in the next line have a deferred release, which is called when the scope is exited – synchronous acquisition followed by asynchronous release.

This originated in C++ as the ScopeGuard class, by Andrei Alexandrescu and Petru Marginean in 2000, [4] with improvements by Joshua Lehrer,[5] and has direct language support in D via the scope keyword (ScopeGuardStatement), where it is one approach to exception safety, in addition to RAII (see below).

This is analogous to traditional file management (acquire during open, release by explicit close), and is known as the dispose pattern.

However, most modern automatic memory management is non-deterministic, making no guarantees that objects will be destroyed promptly or even at all!

In structured programming, stack resource management is done simply by nesting code sufficiently to handle all cases.

This requires only a single return at the end of the code, and can result in heavily nested code if many resources must be acquired, which is considered an anti-pattern by some – the Arrow Anti Pattern,[10] due to the triangular shape from the successive nesting.