A `ReportView` holding an 8 MB rendered buffer registers `bus.subscribe(new Listener() { public void onEvent(Event e) { refresh(); } })` and is never explicitly unsubscribed. After a few hundred report screens, the heap is gone, and a heap dump's histogram shows `byte[]` as the biggest consumer — which is true and doesn't explain anything. What's actually holding the memory, and what's the one-word category of fix?
The anonymous Listener is a non-static inner class, which means it carries a synthetic field — this$0 — pointing back to the exact ReportView instance that created it, assigned automatically at construction and never mentioned anywhere in the source. As long as the EventBus holds that listener (because nothing ever unsubscribed it), the listener holds this$0, and this$0 holds the entire ReportView, buffer and all. The histogram names byte[] as the biggest single object type, but the thing actually keeping every one of those byte arrays reachable is the small, easy-to-overlook Listener object sitting in the bus's subscriber list — the retaining path is EventBus → Listener → ReportView → byte[], and the fix is to make the listener a static nested class (or a lambda that doesn't capture this), so there's no this$0 at all.