I am not worried at all about the actual memory used, just curios about
the use pattern. It may very well be that my app is not causing it at
all, but rather Tomcat doing something periodically, then GC runs.
If the app is running on the same JVM as some additional code, it's
very likely that code isn't completely idle when it's "idle". To get
the observed behavior you would not need a very high rate of object
creation, depending on the sizes of the objects. Even small objects at
the glacial pace of one every few million clock cycles is sufficient
to rack up 44MB of garbage in two hours.
As long as the sawtooth is level rather than trending upward I
wouldn't worry. If it's trending upward it's accumulating cruft
somewhere and is doomed to eventually die of OOME, probably because a
permanently-reachable collection is growing without bound. But it
doesn't look like that's happening in your case. (If it ever does,
identify the culprit collection. If it's a Map consider using
WeakHashMap. If it's anything else consider changing it from Set<Foo>
or List<Foo> or whatever to <WeakReference<Foo>> and holding a direct
reference to each Foo somewhere else that is discarded once that Foo
is no longer useful. Each WeakReference must be created on a
ReferenceQueue which must be occasionally polled to remove references
from the queue, and remove any that are found also from the
collection. A thread can sleep(1000) then lock and poll the reference
queue until empty, then lock the collection and remove all the polled
reference objects, then sleep again. In fact, there really should be
Soft and WeakFoo collection wrapper classes that do this for you --
hold an internal ReferenceQueue, wrap added items in a reference
object on that queue, are synchronized, and collectively use a worker
thread pool to periodically clean out their queues and dead reference
objects, while also handling dereferencing objects and releasing
resources. Heck maybe I should write and publish WeakList and WeakSet
wrappers ... I may need some myself some day anyway. Soft versions
would make good caches; Weak versions where you want to store
references to objects live elsewhere in a system for whatever reason
but not to otherwise-dead objects, and the collection isn't a map's
keys. A map with weak values might be useful too, for that matter...