Add build option for changing the heap limit (#3005)

This change adds a build option that allows adjusting the garbage
collection heap usage limit, which can be used to fine-tune how often
garbage collection should be triggered.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
This commit is contained in:
Dániel Bátyai 2019-08-06 13:35:26 +02:00 committed by Robert Fancsik
parent dec9dbc926
commit 3b7475b01d
6 changed files with 56 additions and 11 deletions

View File

@ -196,6 +196,21 @@ The default value is 512.
| CMake: | `--DJERRY_GLOBAL_HEAP_SIZE=(int)` |
| Python: | `--heap-size=(int)` |
### Garbage collection limit
This option can be used to adjust the maximum allowed heap usage increase until triggering the next garbage collection, in bytes.
When the total allocated memory size reaches the current gc limit, garbage collection will be triggered to try and reduce clutter from unreachable objects.
If the total allocated memory can't be reduced below the current limit, then the limit will be increased by the amount specified via this option.
Similarly, when the total allocated memory goes well below the current gc limit, the limit is reduced by this amount.
The default value is 1/32 of the total heap size, but not greater than 8192 bytes.
A value of 0 will use the default value.
| Options | |
|---------|----------------------------------------------|
| C: | `-DJERRY_GC_LIMIT=(int)` |
| CMake: | `-DJERRY_GC_LIMIT=(int)` |
| Python: | `--gc-limit=(int)` |
### Stack limit
This option can be used to cap the stack usage of the engine, and prevent stack overflows due to recursion. The provided value should be an integer, which represents the allowed stack usage in kilobytes.

View File

@ -39,6 +39,7 @@ set(JERRY_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocato
set(JERRY_VALGRIND OFF CACHE BOOL "Enable Valgrind support?")
set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stopping?")
set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes")
set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection")
set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes")
# Option overrides
@ -101,6 +102,7 @@ message(STATUS "JERRY_SYSTEM_ALLOCATOR " ${JERRY_SYSTEM_ALLOCATOR})
message(STATUS "JERRY_VALGRIND " ${JERRY_VALGRIND})
message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP})
message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE})
message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT})
message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT})
# Include directories
@ -204,6 +206,11 @@ if(DEFINED JERRY_ATTR_GLOBAL_HEAP)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ATTR_GLOBAL_HEAP=${JERRY_ATTR_GLOBAL_HEAP})
endif()
# Memory usage limit for triggering garbage collection
if(JERRY_GC_LIMIT)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GC_LIMIT=${JERRY_GC_LIMIT})
endif()
# Helper macro to set 0/1 switch as Jerry Defines
macro(jerry_add_define01 NAME)
if(${NAME})

View File

@ -207,6 +207,15 @@
# define JERRY_GLOBAL_HEAP_SIZE (512)
#endif /* !defined (JERRY_GLOBAL_HEAP_SIZE) */
/**
* The allowed heap usage limit until next garbage collection, in bytes.
*
* If value is 0, the default is 1/32 of JERRY_HEAP_SIZE
*/
#ifndef JERRY_GC_LIMIT
# define JERRY_GC_LIMIT 0
#endif /* !defined (JERRY_GC_LIMIT) */
/**
* Maximum stack usage size in kilobytes
*
@ -613,6 +622,9 @@
#if !defined (JERRY_GLOBAL_HEAP_SIZE) || (JERRY_GLOBAL_HEAP_SIZE <= 0)
# error "Invalid value for 'JERRY_GLOBAL_HEAP_SIZE' macro."
#endif
#if !defined (JERRY_GC_LIMIT) || (JERRY_GC_LIMIT < 0)
# error "Invalid value for 'JERRY_GC_LIMIT' macro."
#endif
#if !defined (JERRY_STACK_LIMIT) || (JERRY_STACK_LIMIT < 0)
# error "Invalid value for 'JERRY_STACK_LIMIT' macro."
#endif

View File

@ -50,12 +50,20 @@
/**
* Max heap usage limit
*/
#define CONFIG_MEM_HEAP_MAX_LIMIT 8192
#define CONFIG_MAX_GC_LIMIT 8192
/**
* Desired limit of heap usage
* Allowed heap usage limit until next garbage collection
*
* Whenever the total allocated memory size reaches the current heap limit, garbage collection will be triggered
* to try and reduce clutter from unreachable objects. If the allocated memory can't be reduced below the limit,
* then the current limit will be incremented by CONFIG_MEM_HEAP_LIMIT.
*/
#define CONFIG_MEM_HEAP_DESIRED_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_SIZE / 32, CONFIG_MEM_HEAP_MAX_LIMIT))
#if defined (JERRY_GC_LIMIT) && (JERRY_GC_LIMIT != 0)
#define CONFIG_GC_LIMIT JERRY_GC_LIMIT
#else
#define CONFIG_GC_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_SIZE / 32, CONFIG_MAX_GC_LIMIT))
#endif
/**
* Amount of newly allocated objects since the last GC run, represented as a fraction of all allocated objects,

View File

@ -79,7 +79,7 @@ jmem_heap_init (void)
#endif /* !ENABLED (JERRY_CPOINTER_32_BIT) */
JERRY_ASSERT ((uintptr_t) JERRY_HEAP_CONTEXT (area) % JMEM_ALIGNMENT == 0);
JERRY_CONTEXT (jmem_heap_limit) = CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) = CONFIG_GC_LIMIT;
jmem_heap_free_t *const region_p = (jmem_heap_free_t *) JERRY_HEAP_CONTEXT (area);
@ -140,7 +140,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */
if (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT;
}
if (data_space_p->size == JMEM_ALIGNMENT)
@ -223,7 +223,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */
while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT;
}
break;
@ -252,7 +252,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */
while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT;
}
return malloc (size);
@ -443,9 +443,9 @@ jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data spac
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) > 0);
JERRY_CONTEXT (jmem_heap_allocated_size) -= aligned_size;
while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit))
while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_GC_LIMIT <= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_GC_LIMIT;
}
JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
@ -453,9 +453,9 @@ jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data spac
#else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */
JERRY_CONTEXT (jmem_heap_allocated_size) -= size;
while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit))
while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_GC_LIMIT <= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_MEM_HEAP_DESIRED_LIMIT;
JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_GC_LIMIT;
}
free (ptr);

View File

@ -120,6 +120,8 @@ def get_arguments():
help='enable logging (%(choices)s)')
coregrp.add_argument('--mem-heap', metavar='SIZE', type=int,
help='size of memory heap (in kilobytes)')
coregrp.add_argument('--gc-limit', metavar='SIZE', type=int,
help='memory usage limit to trigger garbage collection (in bytes)')
coregrp.add_argument('--stack-limit', metavar='SIZE', type=int,
help='maximum stack usage (in kilobytes)')
coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper,
@ -195,6 +197,7 @@ def generate_build_options(arguments):
build_options_append('JERRY_LINE_INFO', arguments.line_info)
build_options_append('JERRY_LOGGING', arguments.logging)
build_options_append('JERRY_GLOBAL_HEAP_SIZE', arguments.mem_heap)
build_options_append('JERRY_GC_LIMIT', arguments.gc_limit)
build_options_append('JERRY_STACK_LIMIT', arguments.stack_limit)
build_options_append('JERRY_MEM_STATS', arguments.mem_stats)
build_options_append('JERRY_MEM_GC_BEFORE_EACH_ALLOC', arguments.mem_stress_test)