Java Reference
In-Depth Information
[GC 4416K->318K(15872K), 0.0066670 secs]
[GC 926K->327K(15872K), 0.0040134 secs]
[Full GC 327K->327K(15872K), 0.2674688 secs]
Bundle: org.foo.shell.tty started with bundle id 3
->
Tr y u p d a t i n g t h e l e a k y b u n d l e :
->
update 1
Here, 1 is the
ID
of the leaky bundle, as reported by the
bundles
command. You
should see the heap expand each time you call
update
:
[GC 17857K->16753K(32324K), 0.0376856 secs]
[Full GC 16753K->16750K(32324K), 0.0329633 secs]
If you continue to update the bundle, you'll eventually get an
OutOfMemoryError
:
org.osgi.framework.BundleException:
Activator start error in bundle org.foo.leaky [1].
...
Caused by: java.lang.OutOfMemoryError: Java heap space
...
Unable to execute: update 1
Let's try to analyze this memory leak. Restart the framework with heap dumps enabled:
$
java -XX:+HeapDumpOnOutOfMemoryError -jar launcher.jar bundles
Repeatedly update the leaky bundle until the
OutOfMemoryError
occurs:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1916.hprof ...
Heap dump file created [238744986 bytes in 16.578 secs]
You should now have a heap-dump file in your current working directory. Plenty of
open-source tools work with heap dumps; in this case, you'll use the Eclipse Memory
heap and several useful reports to quickly identify potential leaks. Let's see how it
copes with an
OSG
i application. Figure 8.14 shows the leak suspect report for the cap-
tured heap dump.
Notice how it correctly identifies the
ThreadLocal
as the root of the leak. But can it
tell you what application code was responsible? To find out, click the Details link at
the bottom. Doing so opens a detailed page about the
ThreadLocal
, including the var-
ious thread stacks that created the instances (see figure 8.15). It clearly shows the bun-
dle activator
start()
method is the one responsible for creating all these instances.
With your knowledge of the
OSG
i lifecycle, you can infer that the problem is in the
activator
stop()
method.
To solve this leak, all you need to do is go back to the bundle activator and add a
call to
remove()
the
ThreadLocal
in the
stop()
method. This forces the underlying
data object to be cleared and means the bundle's class loader can be collected on
each update/refresh. You should now be able to continually update the bundle with-
out incurring an
OutOfMemoryError
.