py/gc: Allow the GC heap to be split over multiple memory areas.
This commit adds a new option MICROPY_GC_SPLIT_HEAP (disabled by default) which, when enabled, allows the GC heap to be split over multiple memory areas/regions. The first area is added with gc_init() and subsequent areas can be added with gc_add(). New areas can be added at runtime. Areas are stored internally as a linked list, and calls to gc_alloc() can be satisfied from any area. This feature has the following use-cases (among others): - The ESP32 has a fragmented OS heap, so to use all (or more) of it the GC heap must be split. - Other MCUs may have disjoint RAM regions and are now able to use them all for the GC heap. - The user could explicitly increase the size of the GC heap. - Support a dynamic heap while running on an OS, adding more heap when necessary.
This commit is contained in:
parent
5dbb822ca4
commit
bcc827d695
6
py/gc.h
6
py/gc.h
|
@ -28,9 +28,15 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
void gc_init(void *start, void *end);
|
||||
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
// Used to add additional memory areas to the heap.
|
||||
void gc_add(void *start, void *end);
|
||||
#endif
|
||||
|
||||
// These lock/unlock functions can be nested.
|
||||
// They can be used to prevent the GC from allocating/freeing.
|
||||
void gc_lock(void);
|
||||
|
|
|
@ -606,6 +606,11 @@
|
|||
#define MICROPY_ENABLE_GC (0)
|
||||
#endif
|
||||
|
||||
// Whether the garbage-collected heap can be split over multiple memory areas.
|
||||
#ifndef MICROPY_GC_SPLIT_HEAP
|
||||
#define MICROPY_GC_SPLIT_HEAP (0)
|
||||
#endif
|
||||
|
||||
// Hook to run code during time consuming garbage collector operations
|
||||
#ifndef MICROPY_GC_HOOK_LOOP
|
||||
#define MICROPY_GC_HOOK_LOOP
|
||||
|
|
39
py/mpstate.h
39
py/mpstate.h
|
@ -71,12 +71,11 @@ typedef struct _mp_sched_item_t {
|
|||
mp_obj_t arg;
|
||||
} mp_sched_item_t;
|
||||
|
||||
// This structure hold information about the memory allocation system.
|
||||
typedef struct _mp_state_mem_t {
|
||||
#if MICROPY_MEM_STATS
|
||||
size_t total_bytes_allocated;
|
||||
size_t current_bytes_allocated;
|
||||
size_t peak_bytes_allocated;
|
||||
// This structure holds information about a single contiguous area of
|
||||
// memory reserved for the memory manager.
|
||||
typedef struct _mp_state_mem_area_t {
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
struct _mp_state_mem_area_t *next;
|
||||
#endif
|
||||
|
||||
byte *gc_alloc_table_start;
|
||||
|
@ -87,8 +86,30 @@ typedef struct _mp_state_mem_t {
|
|||
byte *gc_pool_start;
|
||||
byte *gc_pool_end;
|
||||
|
||||
size_t gc_last_free_atb_index;
|
||||
} mp_state_mem_area_t;
|
||||
|
||||
// This structure holds a single stacked block and the area it is on. Used
|
||||
// during garbage collection.
|
||||
typedef struct {
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *area;
|
||||
#endif
|
||||
size_t block;
|
||||
} mp_gc_stack_item_t;
|
||||
|
||||
// This structure hold information about the memory allocation system.
|
||||
typedef struct _mp_state_mem_t {
|
||||
#if MICROPY_MEM_STATS
|
||||
size_t total_bytes_allocated;
|
||||
size_t current_bytes_allocated;
|
||||
size_t peak_bytes_allocated;
|
||||
#endif
|
||||
|
||||
mp_state_mem_area_t area;
|
||||
|
||||
int gc_stack_overflow;
|
||||
MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
|
||||
mp_gc_stack_item_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
|
||||
|
||||
// This variable controls auto garbage collection. If set to 0 then the
|
||||
// GC won't automatically run when gc_alloc can't find enough blocks. But
|
||||
|
@ -100,7 +121,9 @@ typedef struct _mp_state_mem_t {
|
|||
size_t gc_alloc_threshold;
|
||||
#endif
|
||||
|
||||
size_t gc_last_free_atb_index;
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *gc_last_free_area;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
size_t gc_collected;
|
||||
|
|
Loading…
Reference in New Issue