py: Make gc.enable/disable just control auto-GC; alloc is still allowed.
gc.enable/disable are now the same as CPython: they just control whether automatic garbage collection is enabled or not. If disabled, you can still allocate heap memory, and initiate a manual collection.
This commit is contained in:
parent
4029f51842
commit
109c1de015
|
@ -4,23 +4,22 @@
|
||||||
.. module:: gc
|
.. module:: gc
|
||||||
:synopsis: control the garbage collector
|
:synopsis: control the garbage collector
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
.. function:: enable()
|
||||||
|
|
||||||
|
Enable automatic garbage collection.
|
||||||
|
|
||||||
|
.. function:: disable()
|
||||||
|
|
||||||
|
Disable automatic garbage collection. Heap memory can still be allocated,
|
||||||
|
and garbage collection can still be initiated manually using :meth:`gc.collect`.
|
||||||
|
|
||||||
.. function:: collect()
|
.. function:: collect()
|
||||||
|
|
||||||
Run a garbage collection.
|
Run a garbage collection.
|
||||||
|
|
||||||
.. function:: disable()
|
|
||||||
|
|
||||||
Disable the garbage collector.
|
|
||||||
|
|
||||||
.. function:: enable()
|
|
||||||
|
|
||||||
Enable the garbage collector.
|
|
||||||
|
|
||||||
.. function:: mem_alloc()
|
.. function:: mem_alloc()
|
||||||
|
|
||||||
Return the number of bytes of heap RAM that are allocated.
|
Return the number of bytes of heap RAM that are allocated.
|
||||||
|
|
9
py/gc.c
9
py/gc.c
|
@ -28,6 +28,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -68,7 +69,8 @@ STATIC mp_uint_t *gc_pool_end;
|
||||||
STATIC int gc_stack_overflow;
|
STATIC int gc_stack_overflow;
|
||||||
STATIC mp_uint_t gc_stack[STACK_SIZE];
|
STATIC mp_uint_t gc_stack[STACK_SIZE];
|
||||||
STATIC mp_uint_t *gc_sp;
|
STATIC mp_uint_t *gc_sp;
|
||||||
STATIC mp_uint_t gc_lock_depth;
|
STATIC uint16_t gc_lock_depth;
|
||||||
|
uint16_t gc_auto_collect_enabled;
|
||||||
STATIC mp_uint_t gc_last_free_atb_index;
|
STATIC mp_uint_t gc_last_free_atb_index;
|
||||||
|
|
||||||
// ATB = allocation table byte
|
// ATB = allocation table byte
|
||||||
|
@ -163,6 +165,9 @@ void gc_init(void *start, void *end) {
|
||||||
// unlock the GC
|
// unlock the GC
|
||||||
gc_lock_depth = 0;
|
gc_lock_depth = 0;
|
||||||
|
|
||||||
|
// allow auto collection
|
||||||
|
gc_auto_collect_enabled = 1;
|
||||||
|
|
||||||
DEBUG_printf("GC layout:\n");
|
DEBUG_printf("GC layout:\n");
|
||||||
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_alloc_table_start, gc_alloc_table_byte_len, gc_alloc_table_byte_len * BLOCKS_PER_ATB);
|
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_alloc_table_start, gc_alloc_table_byte_len, gc_alloc_table_byte_len * BLOCKS_PER_ATB);
|
||||||
#if MICROPY_ENABLE_FINALISER
|
#if MICROPY_ENABLE_FINALISER
|
||||||
|
@ -375,7 +380,7 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||||
mp_uint_t end_block;
|
mp_uint_t end_block;
|
||||||
mp_uint_t start_block;
|
mp_uint_t start_block;
|
||||||
mp_uint_t n_free = 0;
|
mp_uint_t n_free = 0;
|
||||||
int collected = 0;
|
int collected = !gc_auto_collect_enabled;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
// look for a run of n_blocks available blocks
|
// look for a run of n_blocks available blocks
|
||||||
|
|
5
py/gc.h
5
py/gc.h
|
@ -32,6 +32,11 @@ void gc_lock(void);
|
||||||
void gc_unlock(void);
|
void gc_unlock(void);
|
||||||
bool gc_is_locked(void);
|
bool gc_is_locked(void);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// you can still allocate/free memory and also explicitly call gc_collect.
|
||||||
|
extern uint16_t gc_auto_collect_enabled;
|
||||||
|
|
||||||
// A given port must implement gc_collect by using the other collect functions.
|
// A given port must implement gc_collect by using the other collect functions.
|
||||||
void gc_collect(void);
|
void gc_collect(void);
|
||||||
void gc_collect_start(void);
|
void gc_collect_start(void);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
16
py/modgc.c
16
py/modgc.c
|
@ -24,15 +24,13 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "qstr.h"
|
#include "qstr.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "builtin.h"
|
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "objlist.h"
|
|
||||||
#include "objtuple.h"
|
|
||||||
#include "objstr.h"
|
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
|
||||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||||
|
@ -56,7 +54,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||||
/// \function disable()
|
/// \function disable()
|
||||||
/// Disable the garbage collector.
|
/// Disable the garbage collector.
|
||||||
STATIC mp_obj_t gc_disable(void) {
|
STATIC mp_obj_t gc_disable(void) {
|
||||||
gc_lock();
|
gc_auto_collect_enabled = 0;
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||||
|
@ -64,11 +62,16 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||||
/// \function enable()
|
/// \function enable()
|
||||||
/// Enable the garbage collector.
|
/// Enable the garbage collector.
|
||||||
STATIC mp_obj_t gc_enable(void) {
|
STATIC mp_obj_t gc_enable(void) {
|
||||||
gc_unlock();
|
gc_auto_collect_enabled = 1;
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||||
|
|
||||||
|
STATIC mp_obj_t gc_isenabled(void) {
|
||||||
|
return MP_BOOL(gc_auto_collect_enabled);
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled);
|
||||||
|
|
||||||
/// \function mem_free()
|
/// \function mem_free()
|
||||||
/// Return the number of bytes of available heap RAM.
|
/// Return the number of bytes of available heap RAM.
|
||||||
STATIC mp_obj_t gc_mem_free(void) {
|
STATIC mp_obj_t gc_mem_free(void) {
|
||||||
|
@ -92,6 +95,7 @@ STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_isenabled), (mp_obj_t)&gc_isenabled_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "nlr.h"
|
#include "nlr.h"
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
|
@ -470,6 +470,7 @@ Q(gc)
|
||||||
Q(collect)
|
Q(collect)
|
||||||
Q(disable)
|
Q(disable)
|
||||||
Q(enable)
|
Q(enable)
|
||||||
|
Q(isenabled)
|
||||||
Q(mem_free)
|
Q(mem_free)
|
||||||
Q(mem_alloc)
|
Q(mem_alloc)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,12 @@ def h():
|
||||||
g(i) # default arg (second one)
|
g(i) # default arg (second one)
|
||||||
g(i, i) # 2 args
|
g(i, i) # 2 args
|
||||||
|
|
||||||
# call h with heap allocation disabled
|
# call h with heap allocation disabled and all memory used up
|
||||||
gc.disable()
|
gc.disable()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
'a'.lower # allocates 1 cell for boundmeth
|
||||||
|
except MemoryError:
|
||||||
|
pass
|
||||||
h()
|
h()
|
||||||
gc.enable()
|
gc.enable()
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
Loading…
Reference in New Issue