Context
A resource leak occurs when an application does not close all the resources it opens. As an offending application gradually consumes more resources, the supply available for other applications similarly depletes. This is called a leak because system storage slowly diminishes and performance gradually degrades much like a tire losing air.
Resource leaks are a common software defect and are often difficult to debug. Developer tests do not necessarily identify leaks, since automated unit test suites do not usually run long enough for leaks to noticeably affect the system. In addition, isolated test environments often involve only a small number of users or sessions. This is not enough for subtle leaks to impact performance or utilization.
Integration testers or end-users tend to be the first to notice a resource leak's symptoms. They may notice performance or scalability problems or errors indicating that no more resources are available. Unfortunately, these symptoms do not offer any suggestions about the source of the leak. To make matters worse, it is often extremely difficult for programmers to recreate resource leaks in their debugging environment, so they are usually left to pore over the application's resource management code, looking for clues.
The best solution to this problem is to avoid leaks in the first place by employing disciplined resource management strategies. Any module that allocates a resource is ultimately responsible for cleaning it up. Isolating the code that uses a resource within a single component makes it easier to handle all possible conditions.
Unfortunately, despite your best intentions, resource leaks will still occur. Suppose you are responsible for designing a data access library that other developers will use to build applications. Resource utilization depends heavily on the quality of the application code.
At an even higher level, end-users can cause similar symptoms. For example, a graphical application that incorporates the contents of a large set of query results into its user interface needs to keep the corresponding physical result set open so that it can fetch additional data as the user scrolls down. Depending on the exact database implementation, leaving a result set open may prevent other users from updating one or more of its rows. It is common for users to vacate their desks without closing all open application forms, essentially rendering some data inaccessible to others.
Garbage collection offers a promise for a solution. Programming platforms like Java and C# automatically free memory that your code allocated but no longer references. This works quite well for fine-grained objects like buffers and internal data structures. However, it is not usually effective for database resources because most resource managers and database drivers retain references to each resource they create. These references prevent garbage collectors from identifying them as objects that are no longer needed.
The Resource Timer pattern offers a more refined solution. A timer keeps track of a resource's inactivity. A resource is inactive when an application has not invoked any of its operations. A resource timer expires when it reaches its inactivity threshold. This is the interval that the timer waits before automatically cleaning up an inactive resource. A resource timer does this work independently of application code so that leaks caused by application defects or user behavior get resolved over time.
You can build resource timers to work with a variety of resource types. However, it is up to each type of resource to precisely define what activity it entails and what cleaning operations occur automatically when the resource is inactive.
Some examples of where you can readily apply the Resource Timer pattern include:
An open result set often locks rows or tables, preventing other applications from reading or updating them. You can use a resource timer to automatically close a result set if its application does not fetch any of its data or explicitly close it within a designated period of time. An active transaction nearly always locks database objects that are involved in it, and this prevents other applications from accessing them. You can use a resource timer to automatically roll back a transaction if its application neglects to execute subsequent operations within its context or explicitly commit it or roll it back within a designated period of time. A pooled resource that is not returned to its pool prevents it from being recycled for use by other components. This ultimately causes the resource pool to initialize more resources than it otherwise requires. You can use a resource timer to automatically return inactive resources to the pool after a designated period of time.
 |