Resource management (computing): Difference between revisions

Content deleted Content added
m top: links
Complex relationships: Elab with .NET examples
Line 86:
When multiple objects rely on a single resource, resource management can be complicated.
 
A fundamental question is whether a "has a" relationship is one of ''owning'' another object ([[object composition]]), or ''viewing'' another object ([[object aggregation]]). A common case is when one two objects are chained, as in [[pipe and filter]] pattern, the [[delegation pattern]], the [[decorator pattern]], or the [[adapter pattern]]. If the second object (which is not used directly) holds a resource, is the first object (which is used directly) responsible for managing the resource? This is generally answered identically to whether the first object ''owns'' the second object: if so, then the owning object is also responsible for resource management ("having a resource" is [[transitive relation|transitive]]), while if not, then it is not. Further, a single object may "have" several other objects, owning some and viewing others.
 
Both cases are commonly found, and conventions differ. Having objects that use resources indirectly be responsible for the resource (composition) provides [[Encapsulation (computer programming)|encapsulation]] (one only needs the object that clients use, without separate objects for the resources), but results in considerable complexity, particularly when a resource is shared by multiple objects or objects have complex relationships. If only the object that directly uses the resource is responsible for the resource (aggregation), relationships between other objects that use the resources can be ignored, but there is no encapsulation (beyond the directly using object): the resource must be managed directly, and might not be available to the indirectly using object (if it has been released separately).
 
Implementation-wise, in object composition, if using the dispose pattern, the owning object thus will also have a <code>dispose</code> method, which in turn calls the <code>dispose</code> methods of owned objects that must be disposed; in RAII this is handled automatically (so long as owned objects are themselves automatically destroyed: in C++ if they are a value or a <code>unique_ptr</code>, but not a raw pointer: see [[pointer ownership]]). In object aggregation, nothing needs to be done by the viewing object, as it is not responsible for the resource.
 
Both are commonly found. For example, in the [[Java Class Library]], <code>[https://docs.oracle.com/javase/8/docs/api/java/io/Reader.html#close-- Reader#close()]</code> closes the underlying stream, and these can be chained. For example, a <code>[https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html BufferedReader]</code> may contain a <code>[https://docs.oracle.com/javase/8/docs/api/java/io/InputStreamReader.html InputStreamReader]</code>, which in turn contains a <code>[https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html FileInputStream]</code>, and calling <code>close</code> on the <code>BufferedReader</code> in turn closes the <code>InputStreamReader</code>, which in turn closes the <code>FileInputStream</code>, which in turn releases the system file resource. Indeed, the object that directly uses the resource can even be anonymous, thanks to encapsulation:
 
<source lang="Java">
Line 97 ⟶ 99:
}
// reader is closed when the try-with-resources block is exited, which closes each of the contained objects in sequence.
</source>
 
However, it is also possible to manage only the object that directly uses the resource, and not use resource management on wrapper objects:
<source lang="Java">
try (FileInputStream stream = new FileInputStream(fileName)))) {
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
// Use reader.
}
// stream is closed when the try-with-resources block is exited.
// reader is no longer usable after stream is closed, but so long as it does not escape the block, this is not a problem.
</source>
 
Line 108 ⟶ 120:
# Nothing is done to r, but the underlying f is closed, so r cannot be used either.
</source>
 
In [[.NET]], convention is to only have direct user of resources be responsible: "You should implement IDisposable only if your type uses unmanaged resources directly."<ref name="idisposable">{{cite web |url=https://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx |title=IDisposable Interface |accessdate=2016-04-03}}</ref>
 
In case of a more complicated [[object graph]], such as multiple objects sharing a resource, or cycles between objects that hold resources, proper resource management can be quite complicated, and exactly the same issues arise as in object finalization (via destructors or finalizers); for example, the [[lapsed listener problem]] can occur and cause resource leaks if using the