This is a somewhat complex memory leak made even more complex by my only vague familiarity with AngularJS. I will do my best to explain what is going on!
compileAngularComponents is to blame; specifically, this line:
The call to
$compile causes AngularJS to register the
$destroy handler on the element's scope. However, the scope is never destroyed -- it is re-used across dashboard visits.
Is it possible to destroy and re-create the scope when you redraw the dashboard? If not, then perhaps you can remove all of these listeners as a hackfix when the dashboard is redrawn?
Alternatively, are you supposed to re-compile these widgets when you revisit the dashboard? I honestly don't know. :-)
To measure the impact of this leak on Piwik's heap size, I hackfixed the leak by simply removing the line in Angular JS that adds the listener. Here is the result: