for the menus, I created this little script to check the QObject heap:
(
{
var obj, newObj;
{
newObj = QObject.heap.collect(_.class).as(Set).asArray.collect({ |class|
[ class, QObject.heap.select({ |x| x.class == class }).size ]
}).sort({ |a,b| a[1] >= b[1] });
if( obj != newObj ) {
Date.localtime.postln;
newObj.do(_.postln);
"".postln;
obj = newObj;
};
2.0.wait;
}.loop;
}.fork( AppClock )
)
It posts whenever a change occurs in the heap, and lists the number of objects for each class. If you create a GUI window you’ll see the Views and the Window in here, and if you close it they go away again. Now, if you create a Menu like so:
x = Menu( MenuAction("hi") ).front;
you will see it generates actually two MenuActions and a Menu:
[ class MenuAction, 2 ]
[ class Menu, 1 ]
These stay there indefinitely, meaning that they are (probably) not garbage collected (also if I don’t assign the Menu to a variable as I did here). I once let this script run overnight and nothing had changed the next morning. If you do:
x.destroy
the script gives:
[ class MenuAction, 2 ]
so the Menu disappears, the two MenuActions stay. Why two, I only created one? Well, in the Menu:front method it actually creates an empty one. This is a clear and easy to fix bug. A similar thing happens when registering a Menu with MainMenu.register; it creates an extra new Menu() object for all registered MenuActions every time you register a single one (!), plus some extra MenuActions, none of them ever garbage collected.
This happens in: MainMenu:prBuildAppMenus, which is called every time the MainMenu is updated. So any kind of app menu structure in macOS will cause an enormous amount of stray menus, even if you create it only once. Note that on macOS the MainMenu is the only place to create global key commands, it is a very useful feature.
In any case, while Menu:destroy destroys the menu it doesn’t destroy the actions in it. Also, if you do destroy the MenuActions (they can of course be assigned to variables) there is still that extra MenuAction generated in Menu:front that won’t get destroyed.
In Unit-Lib I’m creating a lot of Menu’s and MenuActions on the fly, creating a very user-friendly and quick workflow with clean structures of popup menus with submenus, something that PopUpMenu can’t do. Knowing the above I’m now making sure to destroy each of them after use with my own .deepDestroy method (usually at window close), only create them at the moment when they become necessary and once created keep them in tact instead of re-creating at every click. And of course I made a version of .front that doesn’t create an extra MenuAction. For the MainMenu issue I haven’t found a fix yet, that is a bit too deep in the program to alter stuff, I once tried a ‘registerNoUpdate’ method, updating only after adding all menus, but that was not very stable. I’m not entirely sure if the build-up of Menu/MenuAction objects in the QObject heap has caused actual crashes (it could be that the crashes I had were all caused by QPalette and/or QImage) but it caused a clearly visible memory buildup over time, especially when after a while 10.000s of MenuActions were sitting there…
The uFront and deepDestroy methods I created are in the Unit-Lib quark.
cheers,
Wouter