From a security point of view, Java's garbage collection feature provides significant benefits over traditional languages such as C and C++. The garbage collector (GC) is designed to automatically reclaim unreachable memory and as a result avoid memory leaks. While Although it is quite adept at performing this task, a malicious attacker can nevertheless launch a Denial of Service (DoS) attack, for example by inducing abnormal heap memory allocation as or well as abnormally prolonged object retention.
For example, some versions of the GC needs may need to halt all executing threads in order to keep up with the incoming allocation requests that command trigger increased heap management in terms of space allocationactivity. System throughput rapidly diminishes in this scenario. Real-time systems in particular, are vulnerable to a more subtle slow heap exhaustion DoS attack, perpetrated by stealing CPU cycles. An attacker can source perform memory allocations in a way that keeps increases resource consumption (such as CPU, battery power, memory) high without triggering an OutOfMemoryError
.
Writing garbage collection friendly code helps restrict many attack avenues. The Many of the best practices have been collated and are enumerated below.
Use Short-Lived Immutable Objects
Wiki Markup |
---|
Since JDK 1.2, the new generational garbage collector has reduced memory allocation related costs to minimallow levels, in evenmany cases lesserlower than C/C++. DeallocationImproved hasgarbage alsocollection becomealgorithms cheaperhave such thatreduced the cost of garbage collection so that it is commensurateproportional withto the number of _live_ objects in the _younger generation_, andrather than notto the _total_ number of objects allocated since the last run. Memory is managed in generations to optimize the collectiongarbage collection. Generational garbage collection reduces garbage collection costs by grouping objects into generations. The _younger generation_ consists of short-lived objects. A The GC performs a minor collection on the younger generation is performed when it fills up with dead objects \[[Oracle 2010a|AA. Bibliography#Oracle 10a]\]. |
Wiki Markup |
---|
Note that objects in the _younger generation_ that persist for longer durations are _tenured_ and are moved to the _tenured generation_. Very few _younger generation_ objects continue to live through to the next garbage collection cycle; the rest become ready to be collected in the impending collection cycle \[[Oracle 2010a|AA. Bibliography#Oracle 10a]\]. |
With generational GCs it is advantageous to , use of short-lived immutable objects instead is generally more efficient than use of long-lived mutable objects. Object pools are examples of the latter and should be avoided to increase , such as object pools. Avoiding object pools improves the garbage collector's efficiency. Moreover, object pools Object pools bring additional costs and risks: they can create synchronization problems, deallocations have to be managed explicitly leading to dangers of dangling pointers, and the size of the pool plays a dominant role in mission critical code. Exceptions to this recommendation can be made when the allocation takes longer in comparisonand can require explicit management of deallocations, which risks problems with dangling pointers. Further, determining the correct amount of memory to provision for an object pool can be difficult; this is especially problematic for mission critical code. Use of long-lived mutable objects remains appropriate in cases where allocation of objects is particularly expensive, such as when performing multiple joins across databases or when using objects that . Similarly, object pools are an appropriate design choice when the objects represent scarce resources such as thread pools and database connections.
...
Compliant Solution
This compliant solution highlights uses a custom container called ImmutableHolder
. To aid garbage collection, it is recommended that short-lived ImmutableHolder
objects be created by passing Hashtable
instances to the constructor.
...
Avoid Large Objects
The allocation for of large objects is expensive and ; further, the initialization cost to initialize their fields is proportional to their size. Sometimes Additionally, frequent allocation of large objects of different sizes can cause fragmentation issues or non compacting collect.
...
The new IO classes (NIO) in java.nio
allow the creation and use of direct buffers. These buffers tremendously increase throughput for repeated IO activities, however. However, their creation and reclamation for one-time use is more expensive than that for heap-based non-direct buffers. This is because , because direct buffers are managed using OS specific native code is used to manage them. An OutOfMemoryError
may result if large objects are allocated frequently using this technique. This added management cost makes direct buffers an poor choice for single-use or infrequently used cases. Direct buffers are also not subject to Java's garbage collector which may can cause memory leaks. Frequent allocation of large direct buffers can cause an OutOfMemoryError
.
Noncompliant Code Example
This noncompliant code example uses a short-lived local object buffer
. The buffer
, which is allocated in non-heap memory and is not garbage collected.
...
Reference nulling to "help the garbage collector" is unnecessary. In fact, it just It adds clutter to the code and sometimes introduces can introduce subtle bugs. Assigning null
to local variables is also not very useful as unnecessary; the Java Just-In-Time compiler (JIT) can equivalently do a perform an equivalent liveness analysis — most implementations do this. A related bad practice is to use of a finalizer to null
out references. This practice can cause a huge performance hit; see OBJ08-J. Avoid using finalizers for additional details.
Noncompliant Code Example
...
Wiki Markup |
---|
This compliant solution adds a improveslexical byblock narrowingto downlimit the scope of the variable {{buffer}} so; that the garbage collector collectscan collect the object asimmediately soon aswhen it goes out of scope \[[Bloch 2008|AA. Bibliography#Bloch 08]\]. |
...
Array based data structures such as ArrayLists
are exceptions because the programmer has may be required to explicitly set a few of the individual array elements to null
to indicate their absence or demise.
Long-Lived Objects Containing Short-Lived Objects
Always remove short-lived objects from the long-lived container objects when the task is over. For example, objects attached to a java.nio.channels.SelectionKey
object must be removed when they are no longer needed. Doing so reduces the possibility of memory leaks.
...
The garbage collector can be explicitly invoked by calling the System.gc()
method. Even though the documentation says that it "Runs the garbage collector", there is no guarantee on when the garbage collector will actually run because ; in fact, the call only suggests that it the GC will subsequently execute. Other reasons include the followingto avoid explicit invocation of the GC include:
- Irresponsible use of this feature can severely degrade system performance as the garbage collector would not wait by triggering garbage collection at inopportune moments, rather than waiting until ripe periods when it is safe to garbage collect without interrupting significant interruption of the program's execution significantly.
- The application does not have enough information available lacks sufficient information on when to call
System.gc()
.
In the Java Hotspot VM (default since JDK 1.2), System.gc()
does forces an explicit garbage collection. Sometimes these Such calls are can be buried deep within libraries and are hard difficult to trace. To ignore the call in such cases, use the flag -XX:+DisableExplicitGC
. To avoid long pauses while doing a full GC, a less demanding concurrent cycle can be invoked by specifying the flag -XX:ExplicitGCInvokedConcurrent
.
There are some exceptions to this recommendation. The garbage collector can be explicitly called when the When an application goes through several phases like the such as an initialization and the a ready phase. The heap needs to be compacted between these , it may require heap compaction between phases. Given an uneventful period, System.gc()
may be explicitly invoked in this case. Also, it may such cases, provided that there is a suitable uneventful period between phases. System.gc()
may also be invoked as a last resort in a catch
block that is attempting to recover from an OutOfMemoryError
.
...
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OBJ13-J | low | likely | high | P3 | L3 |
...
TODO
Related Vulnerabilities
...
Wiki Markup |
---|
\[[API 2006|AA. Bibliography#API 06]\] Class {{System}} \[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 6: "Eliminate obsolete object references" \[[Commes 2007|AA. Bibliography#Commes 07]\] Garbage Collection Concepts and Programming Tips \[[Goetz 2004|AA. Bibliography#Goetz 04]\] \[[Lo 2005|AA. Bibliography#Lo 05]\] \[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 6: "Eliminate obsolete object references" \[[MITRE 2009|AA. Bibliography#MITRE 09]\] [CWE ID 405|http://cwe.mitre.org/data/definitions/405.html] "Asymmetric Resource Consumption (Amplification)" |
...