Duffymo ha quasi certamente ragione. In passato, quando abbiamo avuto perdite di memoria, è praticamente SEMPRE il driver JDBC di MySQL. Dimenticando solo di chiudere un piccolo ResultSet o Connection o Statement da qualche parte. Ho finito per controllare l'intera base di codice ogni volta che li usavamo per trovare il problema e assicurarci che venissero chiusi.
Per quanto riguarda l'HashMap, l'ho visto anche io. Non ho esaminato la fonte, ma la mia impressione è stata che il driver MySQL memorizzasse internamente le righe (almeno i valori di riga) in HashMaps.
La perdita di ResultSets è purtroppo facile. L'idea di quelle risorse richiudibili che se ne occupano da sole che arrivano in JDK 7 o 8 mi attira davvero per questo motivo.
Potresti inserire una classe shim da qualche parte (diciamo per Connection) per registrare ogni risorsa aperta/chiusa per vedere se riesci a individuare dove si trova la perdita senza leggere direttamente tutta la tua fonte.