slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
16.93k stars 568 forks source link

Is there a way to release memory used by Image object ? #3029

Closed hbhong closed 10 months ago

hbhong commented 1 year ago

I'm working on a project based on ESP32 C3, which has limited memory, after defining many icons in the slint file, the program can not be compiled and linked. after trying many ways, I found I can load the Image by rust, and return it to Slint with callback function. it works, and also my final image file from 9M was reduced to 3M. But there is a new issue, I noticed once the image is loaded by some component, it can not be released anymore, so when I am running some function worked before, it always crash due to memory is not enough.

hunger commented 1 year ago

The component should clean up all the resources it uses. Components themselves are reference counted, so those should get deleted once the last reference to it is destroyed.

ogoffart commented 1 year ago

You are on bare metal, right?

The compiler puts the image data in flash. It is possible, using environment variable and linker script to specify what section of the flash the image goes (if that helps)

The Image themselves should not be in RAM so they shouldn't take memory. How did you measure that it was the Image taking memory?

hbhong commented 1 year ago

@hunger

The component should clean up all the resources it uses. Components themselves are reference counted, so those should get deleted once the last reference to it is destroyed.

I return the Slint::Image object from the callback, and I just put a debug statement to record which image is returned. and I found the image is only loaded once. if as you said, does it means the component doesn't unload, so the referred image isn't destroyed?

hbhong commented 1 year ago

@ogoffart

You are on bare metal, right?

no, the esp-rs provides std and bare metal two implementations, I'm using std crate.

The Image themselves should not be in RAM so they shouldn't take memory.

yes, I just found if I define the image in the slint file, the final image size is more than 9M, but when I return the images from callback function, it reduces to the 3M, What caused the size of the image to decrease?

How did you measure that it was the Image taking memory?

for now , I haven't a tool to check the detail of runtime memory. I just found when I removed the two images (these two image's size are 90X90 pixels and 50X50) from the component, or replace them with 28X28, it doesn't report memory error. So I think the Image object should use a lot of room in memory.

ogoffart commented 1 year ago

So when you use EmbedResourcesKind::EmbedForSoftwareRenderer, the image is stored in flash uncompressed, but is never put in the RAM If you return it from a callback function, then it is going to be uncompressed in RAM. The image is reference counted. So its memory is freed once no longer in used (no longer stored in a property of a component)

But if you do Image::load_from_path, it will also store the image content in a cache, which is about 5MiB big: https://github.com/slint-ui/slint/blob/6db1c44d2a15bf78b9e819e67560f8f81e6f1ebc/internal/core/graphics/image/cache.rs#L48

There isn't really a way right now to control this cache.

hbhong commented 1 year ago

@ogoffart Thank you for your answer, I create the Image with Image::from_rgba8_premultiplied(), I think it doesn't put the image into the cache.

tronical commented 1 year ago

For the Slint::Image object, is there a way to release resources, I hope it can be released, and loaded again when the component is loaded instead of keeping them in memory.

The image object uses reference counting behind the scenes, so if you have an Image{} element in your scene where you want to release the memory it's holding, just set its source to a default constructed slint::Image. That should replace it with the one you set earlier with Image::from_rgba8_premultiplied().

tronical commented 1 year ago

@hbhong are you still seeing this problem? Could you try the workaround of setting an empty image and see if that release your heap pressure?

ogoffart commented 10 months ago

Please re-open if you can still reproduce the issue. And with more information about how we could also try to reproduce it.