Resource management is very important if you want to write computer programs that behave properly. Resource here refers to anything that you would need to acquire and release inside your program, such as memory, file, network socket, etc. If the resources are not managed well, it may lead to resource leakage. Therefore, we need to ensure that resources are properly released under all circumstances. In this blog, I describe a few patterns used in different programming languages for resource management.
C++: RAII
RAII stands for resource acquisition is initialization. It means that in object-oriented languages, the lifetime of the resource should correspond to the object associated with the resource. Therefore, we could acquire the resource inside the constructor and release it inside the destructor. RAII is commonly used in C++, as object destructor is exception-safe in C++, meaning it will be called even if an exception is raised.
#include <fstream>
int main()
{
std::ifstream myfile("/tmp/myfile");
return 0;
}
In the example above, we pass the file path to the constructor so the resource is automatically acquired while
creating the myfile
object, and the file will be closed when the destructor is called because std::ifstream
follows the RAII idiom.
Golang: defer
In Golang, there is no constructor and destructor. However, we could still manage the resources well with
the defer
statement. A defer
statement inside Golang program indicates that you want something to be
executed, but only at the end of the enclosing function. Just like the destructor in C++, defer
in Golang
is “exception-safe” (should I say “panic-safe”?) so that these defer
ed statements will be called no matter if a function returns normally
or panics.
package main
import "os"
func main() {
myfile := os.Open("/tmp/myfile")
defer myfile.Close()
}
With defer
, you can ensure this file gets closed no matter what. However, you still need to remember to add the call to Close()
.
I feel that it’s less convenient compared to RAII in C++, but I guess this is the best you can do in Golang since
there is only struct
and interface
in Golang and that Golang is garbage-collected.
Java: try-catch-finally
and try-with-resources
Prior to Java 1.7, resource management is done with the try-catch-finally
block. In the try-catch-finally
pattern, you acquire the resources inside the try
block and close them inside the finally
block. The finally
block will always be executed so the resources could be closed properly with and without any exception.
BufferedReader br = null;
try {
br = new BufferedReader(new Filereader("/tmp/myfile"));
} catch (IOException e) {
e.printStackTrace();
} finally {
br.close();
}
With Java 1.7, a new mechanism called try-with-resources
has been introduced. This removes the need to use
the finally
block and it requires the classes of the objects you created implement the AutoCloseable
interface.
The interface simply ensures that a close()
function is implemented for a class.
try (BufferedReader br = new BufferedReader(new FileReader("/tmp/myfile"))) {
br.readLine();
}
In my opinion, the way resources are managed is not as nice as how C++ and Go do it. You introduce
a new level of indentation with each try
block (if you code nicely of course). This could easily decrease code
readability if you have a few nested try
blocks because you need to open different resources at different stages
of a function. I understand that Java, like Go, doesn’t have destructor for classes because it’s garbage-collected.
However, the Go way of using defer
just looks nicer. That being said, you don’t have to manually call close()
with the new try-with-resources
style, so there is no absolute winner on resource management between Go and Java.
Conclusion
In this blog post, I introduced a few ways resources are managed in different programming languages. The idea is not to come up with the best way how resource management should be done (although personally I like RAII the best), but rather to just let you know how things are done out there in some real programming languages. I hope you find this an interesting read. Let me know your own opinions on this topic!
References
- Resource Management (Computing)
- Automatic resource management in Java
- Defer, Panic, and Recover - The Go Blog
- Resource acquisition is initialization