Version 8.3.3 on Linux using DRI and standard memory management (malloc, realloc, free)
Background: We have an object acting as a container which is filled with up to 12 small images used as buttons. They are arranged in two rows and the width of the container therefor is wider as the screen size. The user can then scroll the container with the images left or right so that it’s possible to see all images/buttons and press them. So scrolling to the left will hide the images on the left side and the ones on the right side outside the visible area will become visible, and the other way around.
The problem is that scrolling the container, so that images will be hidden e.g. on the left side and other ones will show up on the right side, and then scrolling back eats up the RAM. If you do it several times the available RAM will completely be used and the application crashes.
Using the trace for the memory I can see that when the first images are leaving the visible area (e.g. when scrolling to the left side as described above) new memory with the size of the used images is allocated. When scrolling back memory is freed, but at least memory for one image isn’t freed anymore. And this explains why the complete RAM is used if you scroll force and back several times because every time one memory area (around 7k) is allocated but not freed anymore.
So the first question is, why new memory has to be allocated? The image objects are already created and only have to be hidden or shown when leaving or entering the visible area.
The second statement: Looks like there is a bug inside the scrolling mechanism which allocates memory but does not completely free it again.
Has anyone seen a similar problem? Is there a way to fix it?
I think it’s not related to scrolling but to the images somehow. Do you see the same issue if you replace the images with a label or a button?
I just created a small test this time using buttons instead of images. The size was set to the same one as for the images, but of course the memory used for a button is much smaller.
I only checked the available memory in the system and I see the same behavior. The memory eaten up is of course much smaller, but after each scrolling force and back the available memory in the system becomes smaller.
So it really looks like a scrolling problem.
Hi @peterb1 ,
Would you be able to paste your button test code here please so we can take a look?
Just in case you are unaware, it is best to enclose the code in tags as follows to make it more readable:
```
some code
```
Thank you.
Kind Regards,
Pete
1 Like
lv_obj_t* buttons[12];
void test_scrolling(void)
{
/* Create a container for the buttons and set some background color */
lv_obj_t * frame = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(frame, lv_color_hex(0xffED00), 0);
/* Set the size for the container so it will be wider as the screen width of 1024 px,
but with the same height */
lv_obj_set_size(frame, 2000, lv_pct(100));
/* Now create 12 buttons in two rows inside the container */
for (int i = 0; i < 6; i++) {
buttons[i*2] = lv_btn_create(frame);
lv_obj_set_pos(buttons[i*2], 210 * i, 100);
lv_obj_set_size(buttons[i*2], 199, 163);
buttons[i*2+1] = lv_btn_create(frame);
lv_obj_set_pos(buttons[i*2+1], 210 * i, 400);
lv_obj_set_size(buttons[i*2+1], 199, 163);
}
}
The main part is copied from the lvgl examples and adapted to the target:
int main(void)
{
/* init dri/drm graphic driver */
lv_init();
drm_init();
static lv_disp_draw_buf_t disp_buf;
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
uint32_t dpi = 0;
drm_get_sizes(&disp_drv.hor_res, &disp_drv.ver_res, &dpi);
void *lvgl_buf1 = malloc(disp_drv.hor_res * disp_drv.ver_res * (LV_COLOR_SIZE/8));
if (!lvgl_buf1)
return -1;
void *lvgl_buf2 = malloc(disp_drv.hor_res * disp_drv.ver_res * (LV_COLOR_SIZE/8));
if (!lvgl_buf2)
return -1;
lv_disp_draw_buf_init(&disp_buf, lvgl_buf1, lvgl_buf2, disp_drv.hor_res * disp_drv.ver_res);
disp_drv.draw_buf = &disp_buf;
disp_drv.flush_cb = drm_flush;
disp_drv.wait_cb = drm_wait_vsync;
lv_disp_drv_register(&disp_drv);
evdev_init();
static lv_indev_drv_t indev_drv_1;
lv_indev_drv_init(&indev_drv_1); /* Basic initialization */
indev_drv_1.type = LV_INDEV_TYPE_POINTER;
/* This function will be called periodically (by the library) to get the mouse position and state */
indev_drv_1.read_cb = evdev_read;
lv_indev_drv_register(&indev_drv_1);
/* call the test routine */
test_scrolling();
/*Handle LitlevGL tasks (tickless mode)*/
while(1) {
lv_timer_handler();
usleep(5000);
}
return 0;
}
1 Like
Hi @peterb1 ,
I have tested your code snippet on both the Windows simulator and the Linux simulator with both #define LV_MEM_CUSTOM 1
& #define LV_MEM_CUSTOM 0
and none of the scenarios appear to leak memory, there seems to be a bit of extra allocation the first time scrolling is activated but then it stabilises.
Presumably we are looking at some kind of issue with your particular setup…
Can you share any more info about it, are we likely to be able to recreate it? I use Virtualbox and can do pretty much any PC version of Linux… Are you indeed using PC hardware or something else?
I have no idea of your level of expertise so if you find any of this is trivial, please feel free to ignore! 
One thing which does spring to mind, if you have limited memory or a large amount of fragmentation and you call most implementations of realloc()
functions they may well fail and return NULL
, but they don’t free the original memory. So it’s normally the users responsibility to save a copy of a pointer before calling realloc()
and if it fails free the original pointer, this has been known to cause memory leaks in some applications.
At this point I can’t think of much else to suggest.
Let me know if you can provide any more info.
Kind Regards,
Pete
Thanks for the feedback. Looks like no one else have seen this problem.
We are using an Arm based target and therefore we use the DRI driver. I believe you are using SDL, correct?
And the calls to realloc are all inside LVGL. So if there at any place a NULL pointer is returned I hope it will be handled correctly.
I will dig more into the code hoping to find the reason. But I first wanted to see if someone already solved this problem. When I find it and solved it I can provide a feedback.
Hi @peterb1 ,
Yes I am using SDL for both Windows and Linux (Ubuntu)… I can’t think of any reason why DRI or SDL would behave any differently under these circumstances, but I am sure the reason will reveal itself!
I can’t really comment on the lv_mem.c
code as I haven’t needed to look at it in detail… I expect it would probably assert in the case of an allocation failure.
If there is anything further we can help with please post back here…
Let us know what you find.
Kind Regards,
Pete
I found the reason and it has nothing to do with LVGL.
I used the compiler flag -fsanitize=address to get some more information in case of a crash via libasan. Removing this flag leads to a stable memory usage. I don’t know what libasan is doing but I also saw this behavior on other code. Maybe it’s a combination of LVGL and libasan, but this has to be checked.