Lvgl v9 memory usage

Hello.
I migrated a project from version 8.3 to version 9 and noticed strange behavior when working with memory. In v8:

#define LV_MEM_SIZE (55 * 1024U)          /*[bytes]*/

After upgrading to v9, with the same disign I received messages:

[D] lv_log_cb:84   [7708]:LVGL:[2] [Warn]	(316.094, +316094)	 lv_draw_buf_create: No memory: 200x100, cf: 16, stride: 800, 80000Byte,  lv_draw_buf.c:186
[D] lv_log_cb:84   [7708]:LVGL:[2] [Warn]	(316.094, +0)	 lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later lv_draw.c:376

I tried increasing LV_MEM_SIZE and at a size of 140 * 1024 everything worked. The increase is more than 2 times and this is a lot for an embedded system.
I monitor memory usage and call a function:

void mem_report(void){
    lv_mem_monitor_t mon;

    lv_mem_monitor(&mon);
    DEBUG("Total: %d free: %d max: %d used: %d%%",mon.total_size,mon.free_size,mon.max_used,mon.used_pct);
}

Maximum usage I’ve seen:

[D] mem_report:312  [7671]:Total: 141316 free: 134584 max: 72583 used: 5%

Maximum usage - 72583. But with LV_MEM_SIZE = 100 * 1024 I got “No memory” message.

Why is this happening? How to determine exactly how much memory is needed? Is there any way to reduce memory consumption?

3 Likes

I’m might be late, but someone just linked this topic to me.

2 times larger memory usage is not intended and acceptable for sure. I noticed ~20% memory increase, so I wonder if there is something special on your UI which requires this large memory.

One thing came to my mind: style_clip_corner is handled differently in LVGL v9 and it’s really requires a lot of memory if the radius is large. You can check here if the bottom area is very large. Can it cause the problem?

I didn’t want to “distract” the LVGL issue with a nonrelated issue, but this might be a more appropriate place for it ;-).

So when the “lv_arc” fails to draw, it internally dead-loops LVGL with the following debug messages:

[Warn] lv_draw_buf_create: No memory: 185x43, cf: 16, stride: 740, 31820Byte, 
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later
[Warn] lv_draw_buf_create: No memory: 185x43, cf: 16, stride: 740, 31820Byte, 
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later

–ad infinitum–. Somewhat surprisingly, the ESP32-S3 doesn’t do a WDT timeout reset, but that may have something to do with the environment (PlatformIO hacked to Arduino-ESP32 3.0.1 so I can directly run an RGB LCD panel with the ESP_Panel library.)

The arc also always fails with a “square” draw region, as pictured:
image

The default (“lv_conf_template.h”) memory size is:

#define LV_MEM_SIZE (64 * 1024U)          /*[bytes]*/

but I had to increase that to

#define LV_MEM_SIZE (128 * 1024U)          /*[bytes]*/

to stop LVGL from hanging when trying to render the arcs. (Tried 96KB…it still hangs.)

Normal operation?

EDIT: There’s not much else on the screen for these tests (at this point just an “lv_list” with 3 entries, and an “lv_bar” with a white border). I can do a “pure arc test” with absolutely nothing else on the screen if that’s of value.

Same problem with you.

Maybe it’s the bar. Can you send its code?

Definitely isn’t the bar. I removed all of the other stuff from the screen, so it’s literally just a container with the lv_scale and lv_arc’s in it. Issue remains the same.

Code here:

		lv_obj_t *solarMeter, *solarArcs[3];

		solarMeter = lv_scale_create(lvContainerObj);
		lv_obj_set_size(solarMeter, 250, 250);
		lv_obj_align(solarMeter, LV_ALIGN_TOP_LEFT, LV_PCT(4), LV_PCT(45));
		lv_scale_set_mode(solarMeter, LV_SCALE_MODE_ROUND_INNER);
		lv_obj_remove_flag(solarMeter, LV_OBJ_FLAG_SCROLLABLE);  // Not scrollable.  (Setting the LV_ARCs to >100% causes this to be "scrollable")
		lv_obj_set_style_pad_all(solarMeter, 50, LV_PART_MAIN);
		lv_obj_set_style_radius(solarMeter, LV_RADIUS_CIRCLE, 0);
		lv_obj_set_style_clip_corner(solarMeter, true, 0);
		//DEBUG
//		lv_obj_set_style_border_color(solarMeter, lv_color_white(), LV_PART_MAIN);		// white border
//		lv_obj_set_style_border_width(solarMeter, 1, LV_PART_MAIN);						// set border width

		lv_scale_set_label_show(solarMeter, true);
		lv_scale_set_total_tick_count(solarMeter, 31);
		lv_scale_set_major_tick_every(solarMeter, 5);
		lv_scale_set_post_draw(solarMeter, true);

		lv_obj_set_style_length(solarMeter, 5, LV_PART_ITEMS);
		lv_obj_set_style_length(solarMeter, 10, LV_PART_INDICATOR);
		lv_scale_set_range(solarMeter, 0, 4000);

		lv_scale_set_angle_range(solarMeter, 270);
		lv_scale_set_rotation(solarMeter, 135);

		// Manually add "arc" angles for the solar charger outputs
		for (int idx = 0; idx < 3; idx++) {
			solarArcs[idx] = lv_arc_create(solarMeter);
			lv_arc_set_rotation(solarArcs[idx], 135);
			lv_arc_set_bg_angles(solarArcs[idx], 0, 270);
			lv_arc_set_range(solarArcs[idx], 0, 4000);
			lv_obj_set_style_arc_rounded(solarArcs[idx], 0, LV_PART_MAIN);		// background
			lv_obj_set_style_arc_rounded(solarArcs[idx], 0, LV_PART_INDICATOR);	// actual indicator
			lv_obj_set_style_arc_color(solarArcs[idx], lv_color_make((idx == 2) ? 255 : 0, (idx == 1) ? 255 : 0, (idx == 0) ? 255 : 0), LV_PART_INDICATOR);
			lv_obj_remove_style(solarArcs[idx], nullptr, LV_PART_KNOB);   	// Hide the knob
			lv_obj_remove_flag(solarArcs[idx], LV_OBJ_FLAG_CLICKABLE);  // Not adjustable by click
			lv_obj_set_size(solarArcs[idx], LV_PCT(120 + (idx * 20)), LV_PCT(120 + (idx * 20)));
			lv_obj_center(solarArcs[idx]);
		}

		lv_arc_set_value(solarArcs[0], 2850);
		lv_arc_set_value(solarArcs[1], 5242);
		lv_arc_set_value(solarArcs[2], 3950);

Hmm…weird. With putting this in test form (i.e. “lv_arc_set_value” calls in the class initializer as above), for some reason it doesn’t crash out even with a 64KB LVGL buffer.

So it might be more of an issue with my project to sort out. What doesn’t make sense is that the class initializer and class “update UI” functions are literally called from the exact same thread (only 10 lines apart)–so it’s not like there’s an “out of memory” resulting from a different FreeRTOS thread context.

Plot thickens…

Could you add this in lv_malloc:

if(size > 10000) {
   printf("large alloc\n"); //Add a breakpoint here and see where it was allocated from 
}

Sure. Also did some debugging/testing + enabling verbose LVGL logging.

First, I consolidated a bit of code from the ESP_Panel functionality → merging the “lv_timer_handler()” call into my own FreeRTOS task thread for handling the LVGL UI. Here’s my LVGL page handler routine (not including the ESP_Panel startup stuff):

	// Set the "container" for all pages.  NOTE: This can easily be set to a window object to
	//"contain" the pages in a tabbed UI if desired.
	mainContainer = lv_scr_act();

	TickType_t xLastWakeTime = xTaskGetTickCount();
	uint32_t task_delay_ms = LVGL_PORT_TASK_MAX_DELAY_MS;
	unsigned long uiPollTimer = millis() + 100;
	while (true) {
		//NOTE: the "lvgl_port_v8" puts LVGL tasking in a separate RTOS thread.  This means that we do
		//not have to call the LVGL Timer functionality to keep the screen updated.  
		//We just have to keep track of our responsibilities here.
		// -> 2024-07-12: absolutely no reason to have that split up.  Merged task timer functionality
		//with this loop here.
        if (lvgl_port_lock(-1)) {
            task_delay_ms = lv_timer_handler();

			// Every 100mS (or so!) call UI update function...
			if (millis() > uiPollTimer) {
				uiPollTimer = millis() + 100;

				// Call the "update" function on the currently active screen
				//WILL CRASH if there is no valid screen loaded.
				// Does the screen class need changed?
				if (currentScreenId != ScreenId) {
					// yes, the screen needs to be changed.
					//Trigger the deconstructor in the screen class object.  THIS calls "lv_obj_clean" on the container
					delete currentScreen;
					
					// Create a new screen class with the requested screen.
					switch (currentScreenId = ScreenId)	{	// assign & check
						case screen_Main:	currentScreen = new HomeScreen_Main(mainContainer); break;
						case screen_Cfg: 	currentScreen = new HomeScreen_Cfg(mainContainer); break;
						//Add more screens here as necessary
					}
				} else {
					// call the Update function on the screen class to handle the necessary functionality.
					currentScreen->Update();
				}
			}

            lvgl_port_unlock();

			if (task_delay_ms > LVGL_PORT_TASK_MAX_DELAY_MS) {
				task_delay_ms = LVGL_PORT_TASK_MAX_DELAY_MS;
			} else if (task_delay_ms < LVGL_PORT_TASK_MIN_DELAY_MS) {
				task_delay_ms = LVGL_PORT_TASK_MIN_DELAY_MS;
			}
        }
		xTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(task_delay_ms));  // vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
	}

This is what doesn’t make sense to me: if I put the “lv_arc_set_value()” calls in the class constructor (as per my code example in a prior post), LVGL works fine with a 64KB buffer.
But when the “lv_arc_set_value()” calls are put in the “Update()” function (literally a few lines lower in the exact same context), it fails drawing the "lv_arc"s unless the LVGL buffer is 128KB in size! This simply doesn’t make sense to me.

I used the following for an output debug in “lv_malloc”. “esp_backtrace_print()” outputs a debug backtrace that can be decoded to the entire call stack without stopping execution. (NOTE: if the backtrace output is not complete all the way to the beginning, the PIO “filter_exception_decoder.py” regex will not catch the backtrace.)

if(size > 10000) {
        printf("large alloc (%d bytes)\n", size); //Add a breakpoint here and see where it was allocated from
        esp_backtrace_print(50);
        sleep(1);
    }

Here is the resulting log (removed a lot of the [Trace] lines due to the post being too long!) NOTE: All of the “20003 byte” allocations were successful; LVGL was drawing the “lv_scale” and background of the "lv_arc"s at that point. It’s when the allocations go up to 31363 bytes that LVGL starts drawing the foreground of the "lv_arc"s. After drawing the first block (= the partial render I showed in the GH issue), LVGL goes to a fast loop and just retries the failure over and over again.

[Trace] lv_malloc: allocating 20003 bytes
[Trace] lv_malloc: allocated at 0x3fc9c134
[Info] lv_draw_layer_alloc_buf: Layer memory used: 19 kB

[...]

Backtrace: 0x420138AD:0x3FCAF3C0 0x4200B6BD:0x3FCAF420 0x4200B8A0:0x3FCAF440 0x4200B628:0x3FCAF480 0x42022A2D:0x3FCAF4A0 0x4200B3D6:0x3FCAF4C0 0x4200B41C:0x3FCAF4F0 0x4200B477:0x3FCAF510 0x420224F5:0x3FCAF530 0x420170D6:0x3FCAF560 0x4208A182:0x3FCAF660420054D5:0x3FCAF680 0x4200555A:0x3FCAF6A0 0x42009A2A:0x3FCAF6E0 0x42009D09:0x3FCAF820 0x42009C3C:0x3FCAF900 0x42009D09:0x3FCAFA40 0x42009AE9:0x3FCAFB20 0x42009D09:0x3FCAFC60 0x4200A0B3:0x3FCAFD40 0x4200A213:0x3FCAFD70 0x4200AA31:0x3FCAFDB0 0x420124CC:0x3FCAFE40 0x420033A2:0x3FCAFE60 0x4037FA3E:0x3FCAFEA0
  #0  0x4200555A in lv_obj_send_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:64
  #1  0x42009A2A in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:110
  #2  0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #3  0x42009C3C in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:212 (discriminator 3)
  #4  0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #5  0x42009AE9 in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:161 (discriminator 3)
  #6  0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #7  0x4200A0B3 in refr_obj_and_children at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:790
  #8  0x4200A213 in refr_area_part at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:723
  #9  0x4200AA31 in refr_area at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:650
      (inlined by) refr_invalid_areas at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:566
      (inlined by) _lv_display_refr_timer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:374
  #10 0x420124CC in lv_timer_exec at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:300
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:105
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:63
  #11 0x420033A2 in rtos_hid_tft(void*) at src/display.cpp:62
  #12 0x4037FA3E in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162


[Trace] lv_malloc: allocating 31363 bytes
[Trace] lv_malloc: allocated at 0x3fc9ae94
[Info] lv_draw_layer_alloc_buf: Layer memory used: 30 kB

[...]
large alloc (31363 bytes)


Backtrace: 0x420138AD:0x3FCAF3C0 0x4200B6BD:0x3FCAF420 0x4200B8A0:0x3FCAF440 0x4200B628:0x3FCAF480 0x42022A2D:0x3FCAF4A0 0x4200B3D6:0x3FCAF4C0 0x4200B41C:0x3FCAF4F0 0x4200B477:0x3FCAF510 0x420224F5:0x3FCAF530 0x420170D6:0x3FCAF560 0x4208A182:0x3FCAF660 0x420054D5:0x3FCAF680 0x4200555A:0x3FCAF6A0 0x42009A2A:0x3FCAF6E0 0x42009D09:0x3FCAF820 0x42009C3C:0x3FCAF900 0x42009D09:0x3FCAFA40 0x42009AE9:0x3FCAFB20 0x42009D09:0x3FCAFC60 0x4200A0B3:0x3FCAFD40 0x4200A213:0x3FCAFD70 0x4200AA31:0x3FCAFDB0 0x420124CC:0x3FCAFE40 0x420033A2:0x3FCAFE60 0x4037FA3E:0x3FCAFEA0
  #0  0x420138AD in lv_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/stdlib/lv_mem.c:67
  #1  0x4200B6BD in buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:465
  #2  0x4200B8A0 in draw_buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:495
      (inlined by) lv_draw_buf_create at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:212
  #3  0x4200B628 in lv_draw_layer_alloc_buf at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:373
  #4  0x42022A2D in dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:310
      (inlined by) dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:292
  #5  0x4200B3D6 in lv_draw_dispatch_layer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:255
  #6  0x4200B41C in lv_draw_dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:161
  #7  0x4200B477 in lv_draw_finalize_task_creation at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:138
  #8  0x420224F5 in lv_draw_arc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_arc.c:69
  #9  0x420170D6 in lv_arc_draw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:700
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:676
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:436
  #10 0x4208A182 in lv_obj_event_base at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:86
  #11 0x420054D5 in event_send_core at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:359
  #12 0x4200555A in lv_obj_send_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:64
  #13 0x42009A2A in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:110
  #14 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #15 0x42009C3C in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:212 (discriminator 3)
  #16 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #17 0x42009AE9 in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:161 (discriminator 3)
  #18 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #19 0x4200A0B3 in refr_obj_and_children at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:790
  #20 0x4200A213 in refr_area_part at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:723
  #21 0x4200AA31 in refr_area at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:650
      (inlined by) refr_invalid_areas at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:566
      (inlined by) _lv_display_refr_timer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:374
  #22 0x420124CC in lv_timer_exec at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:300
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:105
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:63
  #23 0x420033A2 in rtos_hid_tft(void*) at src/display.cpp:62
  #24 0x4037FA3E in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162


[Trace] lv_malloc: allocating 31363 bytes
[Info] lv_malloc: couldn't allocate memory (31363 bytes)
[Trace] lv_mem_monitor_core: begin
[Trace] lv_mem_monitor_core: finished
[Info] lv_malloc: used: 10120 ( 16 %), frag:  41 %, biggest free: 31724
[Warn] lv_draw_buf_create: No memory: 245x32, cf: 16, stride: 980, 31360Byte, 
[Trace] lv_free: freeing 0x3fca3344
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later
[Trace] lv_malloc_zeroed: allocating 84 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca2b9c
[Trace] lv_malloc: allocating 64 bytes
[Trace] lv_malloc: allocated at 0x3fca2cd0
[Trace] lv_malloc_zeroed: allocating 24 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca3344
large alloc (31363 bytes)


Backtrace: 0x420138AD:0x3FCAF3C0 0x4200B6BD:0x3FCAF420 0x4200B8A0:0x3FCAF440 0x4200B628:0x3FCAF480 0x42022A2D:0x3FCAF4A0 0x4200B3D6:0x3FCAF4C0 0x4200B41C:0x3FCAF4F0 0x4200B477:0x3FCAF510 0x420224F5:0x3FCAF530 0x42017149:0x3FCAF560 0x4208A182:0x3FCAF660 0x420054D5:0x3FCAF680 0x4200555A:0x3FCAF6A0 0x42009A2A:0x3FCAF6E0 0x42009D09:0x3FCAF820 0x42009C3C:0x3FCAF900 0x42009D09:0x3FCAFA40 0x42009AE9:0x3FCAFB20 0x42009D09:0x3FCAFC60 0x4200A0B3:0x3FCAFD40 0x4200A213:0x3FCAFD70 0x4200AA31:0x3FCAFDB0 0x420124CC:0x3FCAFE40 0x420033A2:0x3FCAFE60 0x4037FA3E:0x3FCAFEA0
  #0  0x420138AD in lv_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/stdlib/lv_mem.c:67
  #1  0x4200B6BD in buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:465
  #2  0x4200B8A0 in draw_buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:495
      (inlined by) lv_draw_buf_create at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:212
  #3  0x4200B628 in lv_draw_layer_alloc_buf at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:373
  #4  0x42022A2D in dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:310
      (inlined by) dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:292
  #5  0x4200B3D6 in lv_draw_dispatch_layer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:255
  #6  0x4200B41C in lv_draw_dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:161
  #7  0x4200B477 in lv_draw_finalize_task_creation at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:138
  #8  0x420224F5 in lv_draw_arc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_arc.c:69
  #9  0x42017149 in lv_arc_draw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:719
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:676
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:436
  #10 0x4208A182 in lv_obj_event_base at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:86
  #11 0x420054D5 in event_send_core at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:359
  #12 0x4200555A in lv_obj_send_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:64
  #13 0x42009A2A in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:110
  #14 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #15 0x42009C3C in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:212 (discriminator 3)
  #16 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #17 0x42009AE9 in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:161 (discriminator 3)
  #18 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #19 0x4200A0B3 in refr_obj_and_children at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:790
  #20 0x4200A213 in refr_area_part at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:723
  #21 0x4200AA31 in refr_area at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:650
      (inlined by) refr_invalid_areas at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:566
      (inlined by) _lv_display_refr_timer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:374
  #22 0x420124CC in lv_timer_exec at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:300
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:105
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:63
  #23 0x420033A2 in rtos_hid_tft(void*) at src/display.cpp:62
  #24 0x4037FA3E in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162


[Trace] lv_malloc: allocating 31363 bytes
[Info] lv_malloc: couldn't allocate memory (31363 bytes)
[Trace] lv_mem_monitor_core: begin
[Trace] lv_mem_monitor_core: finished
[Info] lv_malloc: used: 10268 ( 17 %), frag:  41 %, biggest free: 31724
[Warn] lv_draw_buf_create: No memory: 245x32, cf: 16, stride: 980, 31360Byte, 
[Trace] lv_free: freeing 0x3fca3344
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later
[Trace] lv_malloc_zeroed: allocating 84 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca2d14
[Trace] lv_malloc: allocating 64 bytes
[Trace] lv_malloc: allocated at 0x3fca2d6c
[Trace] lv_malloc_zeroed: allocating 24 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca2db0
large alloc (31363 bytes)


Backtrace: 0x420138AD:0x3FCAF3C0 0x4200B6BD:0x3FCAF420 0x4200B8A0:0x3FCAF440 0x4200B628:0x3FCAF480 0x42022A2D:0x3FCAF4A0 0x4200B3D6:0x3FCAF4C0 0x4200B41C:0x3FCAF4F0 0x4200B477:0x3FCAF510 0x420224F5:0x3FCAF530 0x420170D6:0x3FCAF560 0x4208A182:0x3FCAF660 0x420054D5:0x3FCAF680 0x4200555A:0x3FCAF6A0 0x42009A2A:0x3FCAF6E0 0x42009D09:0x3FCAF820 0x42009C3C:0x3FCAF900 0x42009D09:0x3FCAFA40 0x42009AE9:0x3FCAFB20 0x42009D09:0x3FCAFC60 0x4200A0B3:0x3FCAFD40 0x4200A213:0x3FCAFD70 0x4200AA31:0x3FCAFDB0 0x420124CC:0x3FCAFE40 0x420033A2:0x3FCAFE60 0x4037FA3E:0x3FCAFEA0
  #0  0x420138AD in lv_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/stdlib/lv_mem.c:67
  #1  0x4200B6BD in buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:465
  #2  0x4200B8A0 in draw_buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:495
      (inlined by) lv_draw_buf_create at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:212
  #3  0x4200B628 in lv_draw_layer_alloc_buf at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:373
  #4  0x42022A2D in dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:310
      (inlined by) dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:292
  #5  0x4200B3D6 in lv_draw_dispatch_layer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:255
  #6  0x4200B41C in lv_draw_dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:161
  #7  0x4200B477 in lv_draw_finalize_task_creation at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:138
  #8  0x420224F5 in lv_draw_arc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_arc.c:69
  #9  0x420170D6 in lv_arc_draw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:700
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:676
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:436
  #10 0x4208A182 in lv_obj_event_base at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:86
  #11 0x420054D5 in event_send_core at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:359
  #12 0x4200555A in lv_obj_send_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:64
  #13 0x42009A2A in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:110
  #14 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #15 0x42009C3C in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:212 (discriminator 3)
  #16 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #17 0x42009AE9 in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:161 (discriminator 3)
  #18 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #19 0x4200A0B3 in refr_obj_and_children at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:790
  #20 0x4200A213 in refr_area_part at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:723
  #21 0x4200AA31 in refr_area at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:650
      (inlined by) refr_invalid_areas at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:566
      (inlined by) _lv_display_refr_timer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:374
  #22 0x420124CC in lv_timer_exec at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:300
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:105
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:63
  #23 0x420033A2 in rtos_hid_tft(void*) at src/display.cpp:62
  #24 0x4037FA3E in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162


[Trace] lv_malloc: allocating 31363 bytes
[Info] lv_malloc: couldn't allocate memory (31363 bytes)
[Trace] lv_mem_monitor_core: begin
[Trace] lv_mem_monitor_core: finished
[Info] lv_malloc: used: 10424 ( 17 %), frag:  41 %, biggest free: 31724
[Warn] lv_draw_buf_create: No memory: 245x32, cf: 16, stride: 980, 31360Byte, 
[Trace] lv_free: freeing 0x3fca2db0
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later
[Trace] lv_malloc_zeroed: allocating 84 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca3670
[Trace] lv_malloc: allocating 64 bytes
[Trace] lv_malloc: allocated at 0x3fca36c8
[Trace] lv_malloc_zeroed: allocating 24 bytes
[Trace] lv_malloc_zeroed: allocated at 0x3fca2db0
large alloc (31363 bytes)


Backtrace: 0x420138AD:0x3FCAF3C0 0x4200B6BD:0x3FCAF420 0x4200B8A0:0x3FCAF440 0x4200B628:0x3FCAF480 0x42022A2D:0x3FCAF4A0 0x4200B3D6:0x3FCAF4C0 0x4200B41C:0x3FCAF4F0 0x4200B477:0x3FCAF510 0x420224F5:0x3FCAF530 0x42017149:0x3FCAF560 0x4208A182:0x3FCAF660 0x420054D5:0x3FCAF680 0x4200555A:0x3FCAF6A0 0x42009A2A:0x3FCAF6E0 0x42009D09:0x3FCAF820 0x42009C3C:0x3FCAF900 0x42009D09:0x3FCAFA40 0x42009AE9:0x3FCAFB20 0x42009D09:0x3FCAFC60 0x4200A0B3:0x3FCAFD40 0x4200A213:0x3FCAFD70 0x4200AA31:0x3FCAFDB0 0x420124CC:0x3FCAFE40 0x420033A2:0x3FCAFE60 0x4037FA3E:0x3FCAFEA0
  #0  0x420138AD in lv_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/stdlib/lv_mem.c:67
  #1  0x4200B6BD in buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:465
  #2  0x4200B8A0 in draw_buf_malloc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:495
      (inlined by) lv_draw_buf_create at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_buf.c:212
  #3  0x4200B628 in lv_draw_layer_alloc_buf at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:373
  #4  0x42022A2D in dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:310
      (inlined by) dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/sw/lv_draw_sw.c:292
  #5  0x4200B3D6 in lv_draw_dispatch_layer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:255
  #6  0x4200B41C in lv_draw_dispatch at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:161
  #7  0x4200B477 in lv_draw_finalize_task_creation at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw.c:138
  #8  0x420224F5 in lv_draw_arc at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/draw/lv_draw_arc.c:69
  #9  0x42017149 in lv_arc_draw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:719
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:676
      (inlined by) lv_arc_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/widgets/arc/lv_arc.c:436
  #10 0x4208A182 in lv_obj_event_base at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:86
  #11 0x420054D5 in event_send_core at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:359
  #12 0x4200555A in lv_obj_send_event at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_obj_event.c:64
  #13 0x42009A2A in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:110
  #14 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #15 0x42009C3C in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:212 (discriminator 3)
  #16 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #17 0x42009AE9 in lv_obj_redraw at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:161 (discriminator 3)
  #18 0x42009D09 in refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:892
      (inlined by) refr_obj at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:886
  #19 0x4200A0B3 in refr_obj_and_children at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:790
  #20 0x4200A213 in refr_area_part at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:723
  #21 0x4200AA31 in refr_area at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:650
      (inlined by) refr_invalid_areas at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:566
      (inlined by) _lv_display_refr_timer at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/core/lv_refr.c:374
  #22 0x420124CC in lv_timer_exec at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:300
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:105
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-devkitm-1/lvgl/src/misc/lv_timer.c:63
  #23 0x420033A2 in rtos_hid_tft(void*) at src/display.cpp:62
  #24 0x4037FA3E in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162

One of the 31,363 byte requests succeeds–this is the “top block draw”:
image

What I’m noticing is that the failed allocation requests are 31,363 bytes, but “biggest free” is listed as 31,724 bytes. (This is with a [64 * 1024] LVGL buffer size.)

OK, still testing…

Noticing that it fails at a 64KB buffer, but supposedly is just several hundred bytes away from the “limit”, I tried some larger buffers.

72KB buffer → fails. Despite another 8KB of memory, the biggest “free memory” is the same as with 64KB. Notice the fragmentation of 49% (up from 41% with 64KB buffer):

[Info] lv_malloc: couldn't allocate memory (31363 bytes)
[Info] lv_malloc: used: 10268 ( 15 %), frag:  49 %, biggest free: 31724
[Warn] lv_draw_buf_create: No memory: 245x32, cf: 16, stride: 980, 31360Byte, 
[Warn] lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later
large alloc (31363 bytes)

80KB buffer → succeeds.

It seems something makes LVGL to render to arc on new layer (lv_draw_layer_alloc_buf). Please share your LVGL UI code, so that I can test it locally.

ArcTest causes memory overrun PIO.zip (39.9 KB)
Here you are. Minimal/reduced down code to the minimums, and verified the issue still persists. Intended to run on a 7" Waveshare ESP32-S3 screen: https://www.waveshare.com/esp32-s3-touch-lcd-7.htm

note that it’s a PlatformIO project, hacked to Arduino-ESP32 v3.0.2.

I think the biggest thing potentially causing the issue is whether the “lv_arc_set_value” is called BEFORE the initial screen rendering of the "lv_arc"s, or AFTER.

BEFORE, it works fine. AFTER, we have the memory issue.

but in most dynamic UI systems, most of the “lv_arc_set_value” calls will be AFTER the initial screen rendering (i.e. to update the reading). That’s really the only difference in the example code between putting it in the class initializer (works) vs in “Update()” (out of memory).

Found it! :tada:

It was because of lv_obj_set_style_clip_corner(solarMeter, true, 0);. In v9 it’s less optimal than in v8. Removing it shouldn’t change anything in case of this UI.