[SOLVED] Component memory consumption (Mac)


Is it normal for 3000 Components to use 1.5GB of memory. The Compnents are just empty boxes with a custom background paint. It seems like a lot for something like 500x100px component to use half a MB of memory.

I tried profiling to find what’s going on, but couldn’t really spot it, because the used memory was scattered in the internals. It kinda looked like some CGLayers were hogging a lot of it.

Is the above behaviour as expected? Is it unavoidable or is there some Component configuration that would be more memory efficient?

Do you setBufferedToImage(true) ?

Yes, actually i do. That’s it. Setting it false removes the 1.5GB overhead. Thanks for the tip @chkn !

The bad news for me is that i still might need to have it set. :open_mouth: I guess i need component recycling. Scrolling performance is not too good without buffering to image.

Any other ideas on how to improve performance with preferably a little less memory overhead?

Can you tell us more about your situation? Are you using a ListBox?

Pretty classic, i have a large bunch of audio thumbnails in a scroll view (Viewport). ATM i just fill the entire scrollable view with these. The performance isn’t too bad with efficient use of audio thumbnails, but the buffering makes it smoother anyway. I guess the standard optimization is to have only the components visible or soon to be visible existing and recycle them while scrolling. Maybe i could just disable the buffering when the components aren’t visible or something along those lines.

I left out the audio thumbnail part from my initial question as the overhead wasn’t caused by them at all.

setBufferedToImage(true) does exactly what it promises :wink:

interesting approach, imho that is what modern webbrowsers do, rendering in tiles and draw them gpu optimised

I would try top optimise the waveform drawing first, how do you do that?
Can you draw them with one fillRectList() draw?

Alternative you might want to use openGL commands to draw a vertexArray in the openGL renderCallback (but you need an openGL expert for that, which I am not :wink: ), if you want to use openGL, this is really fast

Does juce::Viewport not already handle the situation of only drawing components that are actually on-screen?

Can you count the number that are being painted in anyway? If they’re only drawn once then a simple DBG in their paint() method would probably do the trick - unless you’re painting them on a timer are you?

@chkn I’m simply painting the waveforms with AudioThumbnail.drawChannel. I don’t know what it does internally, but i believe it’s very efficient. The scrolling is smoother with buffering, even if i paint only simple fillRoundedRect. So i like the buffering. The problem is that having all components buffered takes a lot of memory.

@ImJimmi I believe it does. My problem is not actually rendering overhead. Rendering is fast and smooth with buffered components, it just takes a lot of memory having them all buffered all the time.

The way i see it, the only way to reduce memory consumption while maintaining the smooth scrolling of buffered components, is to make the whole setup more dynamic - one way or the other. Which i would rather not, because it’s so simple and nice as it is. Interested to learn any ideas besides recycling entire components or enabling and disabling the buffering of individual components as needed. The latter is just an idea and might turn out useless at the first try.

It doesn’t cull anything, no. Doing that would involve modifying paintComponentAndChildren() to avoid painting objects outside of the screen/view/component’s bounds (and there are a bunch of other factors).

Doing what @ImJimmi suggested and putting log into the components’ paint certainly outputs only the visible components. That is without buffering. With buffered to image components it paints those only once, while without buffering it repaints the visible components every time the parent repaints i.e. every scroll move.

Not sure we’re talking about the same thing, but there’s a

else if (clipBounds.intersects (child.getBounds()))

in Component.paintComponentAndChildren. I suppose that does it generally to any component outside the area of the ancestry.