The memory leak comes from three sources:
1) The AntiGC thread is sometimes not terminated. This happens when
Derby is shut down right after the driver is loaded, because the
run() method in AntiGC starts with setting a boolean variable which
is used to decide when the thread should stop. The same variable is
set when a request to shut down Derby is sent, and if the shutdown
is requested before the AntiGC thread has started running, the
request to shut down Derby might not be noticed by AntiGC which
will run forever.
Solution: Don't set the boolean variable in AntiGC's run() method. It
is enough that it is being set when the object is initialized.
2) Every time the driver is loaded, a new ThreadGroup is created. They
don't seem to be garbage collected even when all their threads have
Solution: Set the daemon property on the ThreadGroups. This way a
ThreadGroup will be destroyed when its last running thread (or thread
group) is destroyed.
3) The Java Heap Analysis Tool reported that a huge number of
ContextManager and ContextService objects were kept in the
heap. The objects were not accessible from the root set, but they
were not garbage collected, probably because of some cyclic
references which the gc cannot handle.
Solution: Break the reference cycle by nulling out the references to
the lists of ContextManagers when ContextService objects are stopped.
The attached patch seems to fix the problems mentioned above. Derbyall
runs fine, and top reports that the memory usage does not increase
when running a loop where the driver is loaded (with
Class.forName("org...EmbeddedDriver").newInstance()) and unloaded
(with DriverManager.getConnection("jdbc:derby:;shutdown=true")). That
is, the memory usage of course increased during the first iteration,
but not during the approximately 8.5 million next ones.
I will submit tests later.