Refactor memory management (#2954)

This PR is a general cleanup for garbage collection and memory
allocation code paths.

Changes:
  * Removed an unnecesary local variable from 'ecma_gc_mark'.
  * Refactored 'ecma_gc_run' to have an implicit list head during
    iteration, which results in one less condition in the loops,
    and changed the loops to use compressed pointers to reduce the
    overall amount of compression/decompression.
  * Renamed 'jmem_free_unused_memory_severity_t' to 'jmem_pressure_t',
    and added additional values.
  * Removed 'jmem_free_unused_memory_callback', instead
    'ecma_free_unused_memory' is now called directly.
  * Reworked 'ecma_free_unused_memory' to handle all code paths related
    to 'jmem_pressure_t', and moved all relevant code paths into this
    function. This simplifies the code paths in other places.
  * Reworked 'jmem_heap_gc_and_alloc_block' to be more streamlined.
  * Changed mem-stats to not report unused pool chunks as allocated
    memory.
  * Created an allocator internal API for allocating/freeing memory blocks
    that are not reported as used memory in mem-stats.
  * Removed iteration statistics for the jerry allocator from mem-stats,
    as they don't provide any actually useful information.

Co-authored-by: Marko Fabo <mfabo@inf.u-szeged.hu>
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-07-17 14:12:23 +02:00
committed by GitHub
parent a44d584842
commit ff22634e27
27 changed files with 297 additions and 538 deletions
+22 -8
View File
@@ -45,16 +45,11 @@
#endif /* ENABLED (JERRY_VALGRIND) */
/** @} */
#if ENABLED (JERRY_MEM_STATS)
void jmem_heap_stats_reset_peak (void);
void jmem_heap_stats_print (void);
#endif /* ENABLED (JERRY_MEM_STATS) */
void jmem_heap_init (void);
void jmem_heap_finalize (void);
bool jmem_is_heap_pointer (const void *pointer);
void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity);
void *jmem_heap_alloc_block_internal (const size_t size);
void jmem_heap_free_block_internal (void *ptr, const size_t size);
/**
* \addtogroup poolman Memory pool manager
@@ -62,11 +57,30 @@ void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t s
*/
void jmem_pools_finalize (void);
void jmem_pools_collect_empty (void);
/**
* @}
* @}
*/
/**
* @{
* Jerry mem-stat definitions
*/
#if ENABLED (JERRY_MEM_STATS)
void jmem_heap_stat_init (void);
void jmem_heap_stat_alloc (size_t num);
void jmem_heap_stat_free (size_t num);
#define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init ()
#define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1)
#define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1)
#else /* !ENABLED (JERRY_MEM_STATS) */
#define JMEM_HEAP_STAT_INIT()
#define JMEM_HEAP_STAT_ALLOC(v1) JERRY_UNUSED (v1)
#define JMEM_HEAP_STAT_FREE(v1) JERRY_UNUSED (v1)
#endif /* ENABLED (JERRY_MEM_STATS) */
/** @} */
#endif /* !JMEM_ALLOCATOR_INTERNAL_H */
-37
View File
@@ -232,40 +232,3 @@ jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompres
return (void *) uint_ptr;
} /* jmem_decompress_pointer */
/**
* Register specified 'try to give memory back' callback routine
*/
void
jmem_register_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback) /**< callback routine */
{
/* Currently only one callback is supported */
JERRY_ASSERT (JERRY_CONTEXT (jmem_free_unused_memory_callback) == NULL);
JERRY_CONTEXT (jmem_free_unused_memory_callback) = callback;
} /* jmem_register_free_unused_memory_callback */
/**
* Unregister specified 'try to give memory back' callback routine
*/
void
jmem_unregister_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback) /**< callback routine */
{
/* Currently only one callback is supported */
JERRY_ASSERT (JERRY_CONTEXT (jmem_free_unused_memory_callback) == callback);
JERRY_CONTEXT (jmem_free_unused_memory_callback) = NULL;
} /* jmem_unregister_free_unused_memory_callback */
/**
* Run 'try to give memory back' callbacks with specified severity
*/
void
jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity) /**< severity of the request */
{
if (JERRY_CONTEXT (jmem_free_unused_memory_callback) != NULL)
{
JERRY_CONTEXT (jmem_free_unused_memory_callback) (severity);
}
jmem_pools_collect_empty ();
} /* jmem_run_free_unused_memory_callbacks */
+86 -167
View File
@@ -17,6 +17,7 @@
* Heap implementation
*/
#include "ecma-gc.h"
#include "jcontext.h"
#include "jmem.h"
#include "jrt-bit-fields.h"
@@ -65,44 +66,6 @@ jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */
} /* jmem_heap_get_region_end */
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
/**
* @{
* JMEM_HEAP_STAT_xxx definitions
*/
#if ENABLED (JERRY_MEM_STATS)
static void jmem_heap_stat_init (void);
static void jmem_heap_stat_alloc (size_t num);
static void jmem_heap_stat_free (size_t num);
#define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init ()
#define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1)
#define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1)
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
static void jmem_heap_stat_skip (void);
static void jmem_heap_stat_nonskip (void);
static void jmem_heap_stat_alloc_iter (void);
static void jmem_heap_stat_free_iter (void);
#define JMEM_HEAP_STAT_SKIP() jmem_heap_stat_skip ()
#define JMEM_HEAP_STAT_NONSKIP() jmem_heap_stat_nonskip ()
#define JMEM_HEAP_STAT_ALLOC_ITER() jmem_heap_stat_alloc_iter ()
#define JMEM_HEAP_STAT_FREE_ITER() jmem_heap_stat_free_iter ()
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
#else /* !ENABLED (JERRY_MEM_STATS) */
#define JMEM_HEAP_STAT_INIT()
#define JMEM_HEAP_STAT_ALLOC(v1) JERRY_UNUSED (v1)
#define JMEM_HEAP_STAT_FREE(v1) JERRY_UNUSED (v1)
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
#define JMEM_HEAP_STAT_SKIP()
#define JMEM_HEAP_STAT_NONSKIP()
#define JMEM_HEAP_STAT_ALLOC_ITER()
#define JMEM_HEAP_STAT_FREE_ITER()
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
#endif /* ENABLED (JERRY_MEM_STATS) */
/** @} */
/**
* Startup initialization of heap
*/
@@ -156,7 +119,7 @@ jmem_heap_finalize (void)
* NULL - if there is not enough memory.
*/
static void * JERRY_ATTR_HOT
jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block */
jmem_heap_alloc (const size_t size) /**< size of requested block */
{
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
/* Align size. */
@@ -174,7 +137,11 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block
JMEM_VALGRIND_DEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
JERRY_CONTEXT (jmem_heap_allocated_size) += JMEM_ALIGNMENT;
JMEM_HEAP_STAT_ALLOC_ITER ();
if (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
}
if (data_space_p->size == JMEM_ALIGNMENT)
{
@@ -208,12 +175,11 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block
uint32_t current_offset = JERRY_HEAP_CONTEXT (first).next_offset;
jmem_heap_free_t *prev_p = &JERRY_HEAP_CONTEXT (first);
while (current_offset != JMEM_HEAP_END_OF_LIST)
while (JERRY_LIKELY (current_offset != JMEM_HEAP_END_OF_LIST))
{
jmem_heap_free_t *current_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (current_offset);
JERRY_ASSERT (jmem_is_heap_pointer (current_p));
JMEM_VALGRIND_DEFINED_SPACE (current_p, sizeof (jmem_heap_free_t));
JMEM_HEAP_STAT_ALLOC_ITER ();
const uint32_t next_offset = current_p->next_offset;
JERRY_ASSERT (next_offset == JMEM_HEAP_END_OF_LIST
@@ -223,7 +189,6 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block
{
/* Region is sufficiently big, store address. */
data_space_p = current_p;
JERRY_CONTEXT (jmem_heap_allocated_size) += required_size;
/* Region was larger than necessary. */
if (current_p->size > required_size)
@@ -254,6 +219,13 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block
JERRY_CONTEXT (jmem_heap_list_skip_p) = prev_p;
/* Found enough space. */
JERRY_CONTEXT (jmem_heap_allocated_size) += required_size;
while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
{
JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT;
}
break;
}
@@ -264,25 +236,18 @@ jmem_heap_alloc_block_internal (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;
}
JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
if (JERRY_UNLIKELY (!data_space_p))
{
return NULL;
}
JERRY_ASSERT ((uintptr_t) data_space_p % JMEM_ALIGNMENT == 0);
JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, size);
JMEM_HEAP_STAT_ALLOC (size);
#if ENABLED (JERRY_VALGRIND)
if (data_space_p != NULL)
{
JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, size);
}
#endif /* ENABLED (JERRY_VALGRIND) */
return (void *) data_space_p;
#else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */
JMEM_HEAP_STAT_ALLOC (size);
JERRY_CONTEXT (jmem_heap_allocated_size) += size;
while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit))
@@ -292,92 +257,82 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block
return malloc (size);
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
} /* jmem_heap_alloc_block_internal */
} /* jmem_heap_alloc */
/**
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
* Allocation of memory block, reclaiming memory if the request cannot be fulfilled.
*
* Note:
* if there is still not enough memory after running the callbacks
* - NULL value will be returned if parmeter 'ret_null_on_error' is true
* - the engine will terminate with ERR_OUT_OF_MEMORY if 'ret_null_on_error' is false
* Each failed allocation attempt tries to reclaim memory with an increasing pressure,
* up to 'max_pressure', or until a sufficient memory block is found. When JMEM_PRESSURE_FULL
* is reached, the engine is terminated with ERR_OUT_OF_MEMORY. The `max_pressure` argument
* can be used to limit the maximum pressure, and prevent the engine from terminating.
*
* @return NULL, if the required memory size is 0
* also NULL, if 'ret_null_on_error' is true and the allocation fails because of there is not enough memory
* @return NULL, if the required memory size is 0 or not enough memory
* pointer to the allocated memory block, if allocation is successful
*/
static void *
jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */
bool ret_null_on_error) /**< indicates whether return null or terminate
with ERR_OUT_OF_MEMORY on out of memory */
jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */
jmem_pressure_t max_pressure) /**< pressure limit */
{
if (JERRY_UNLIKELY (size == 0))
{
return NULL;
}
#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
jmem_pressure_t pressure = JMEM_PRESSURE_NONE;
#if !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
if (JERRY_CONTEXT (jmem_heap_allocated_size) + size >= JERRY_CONTEXT (jmem_heap_limit))
#endif /* !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
{
jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW);
pressure = JMEM_PRESSURE_LOW;
ecma_free_unused_memory (pressure);
}
void *data_space_p = jmem_heap_alloc_block_internal (size);
void *data_space_p = jmem_heap_alloc (size);
if (JERRY_LIKELY (data_space_p != NULL))
while (JERRY_UNLIKELY (data_space_p == NULL) && JERRY_LIKELY (pressure < max_pressure))
{
JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size);
return data_space_p;
}
for (jmem_free_unused_memory_severity_t severity = JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW;
severity <= JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH;
severity = (jmem_free_unused_memory_severity_t) (severity + 1))
{
jmem_run_free_unused_memory_callbacks (severity);
data_space_p = jmem_heap_alloc_block_internal (size);
if (JERRY_LIKELY (data_space_p != NULL))
{
JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size);
return data_space_p;
}
}
JERRY_ASSERT (data_space_p == NULL);
if (!ret_null_on_error)
{
jerry_fatal (ERR_OUT_OF_MEMORY);
pressure++;
ecma_free_unused_memory (pressure);
data_space_p = jmem_heap_alloc (size);
}
return data_space_p;
} /* jmem_heap_gc_and_alloc_block */
/**
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
* Internal method for allocating a memory block.
*/
inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_alloc_block_internal (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_FULL);
} /* jmem_heap_alloc_block_internal */
/**
* Allocation of memory block, reclaiming unused memory if there is not enough.
*
* Note:
* If there is still not enough memory after running the callbacks, then the engine will be
* terminated with ERR_OUT_OF_MEMORY.
* If a sufficiently sized block can't be found, the engine will be terminated with ERR_OUT_OF_MEMORY.
*
* @return NULL, if the required memory is 0
* pointer to allocated memory block, otherwise
*/
inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_alloc_block (const size_t size) /**< required memory size */
jmem_heap_alloc_block (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, false);
void *block_p = jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_FULL);
JMEM_HEAP_STAT_ALLOC (size);
return block_p;
} /* jmem_heap_alloc_block */
/**
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
* Allocation of memory block, reclaiming unused memory if there is not enough.
*
* Note:
* If there is still not enough memory after running the callbacks, NULL will be returned.
* If a sufficiently sized block can't be found, NULL will be returned.
*
* @return NULL, if the required memory size is 0
* also NULL, if the allocation has failed
@@ -386,15 +341,24 @@ jmem_heap_alloc_block (const size_t size) /**< required memory size */
inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_alloc_block_null_on_error (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, true);
void *block_p = jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_HIGH);
#if ENABLED (JERRY_MEM_STATS)
if (block_p != NULL)
{
JMEM_HEAP_STAT_ALLOC (size);
}
#endif /* ENABLED (JERRY_MEM_STATS) */
return block_p;
} /* jmem_heap_alloc_block_null_on_error */
/**
* Free the memory block.
* Internal method for freeing a memory block.
*/
void JERRY_ATTR_HOT
jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */
const size_t size) /**< size of allocated region */
jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data space of the block */
const size_t size) /**< size of allocated region */
{
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
/* checking that ptr points to the heap */
@@ -404,7 +368,6 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the
JMEM_VALGRIND_FREELIKE_SPACE (ptr);
JMEM_VALGRIND_NOACCESS_SPACE (ptr, size);
JMEM_HEAP_STAT_FREE_ITER ();
jmem_heap_free_t *block_p = (jmem_heap_free_t *) ptr;
jmem_heap_free_t *prev_p;
@@ -415,12 +378,10 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the
if (block_p > JERRY_CONTEXT (jmem_heap_list_skip_p))
{
prev_p = JERRY_CONTEXT (jmem_heap_list_skip_p);
JMEM_HEAP_STAT_SKIP ();
}
else
{
prev_p = &JERRY_HEAP_CONTEXT (first);
JMEM_HEAP_STAT_NONSKIP ();
}
JERRY_ASSERT (jmem_is_heap_pointer (block_p));
@@ -436,8 +397,6 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the
JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
prev_p = next_p;
JMEM_HEAP_STAT_FREE_ITER ();
}
next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset);
@@ -491,9 +450,7 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the
JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t));
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_limit) >= JERRY_CONTEXT (jmem_heap_allocated_size));
JMEM_HEAP_STAT_FREE (size);
#else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */
JMEM_HEAP_STAT_FREE (size);
JERRY_CONTEXT (jmem_heap_allocated_size) -= size;
while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit))
@@ -503,6 +460,18 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the
free (ptr);
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
} /* jmem_heap_free_block_internal */
/**
* Free memory block
*/
inline void JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */
const size_t size) /**< size of allocated region */
{
jmem_heap_free_block_internal (ptr, size);
JMEM_HEAP_STAT_FREE (size);
return;
} /* jmem_heap_free_block */
#ifndef JERRY_NDEBUG
@@ -577,23 +546,12 @@ jmem_heap_stats_print (void)
heap_stats->peak_object_bytes,
heap_stats->property_bytes,
heap_stats->peak_property_bytes);
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
JERRY_DEBUG_MSG (" Skip-ahead ratio = %zu.%04zu\n"
" Average alloc iteration = %zu.%04zu\n"
" Average free iteration = %zu.%04zu\n",
heap_stats->skip_count / heap_stats->nonskip_count,
heap_stats->skip_count % heap_stats->nonskip_count * 10000 / heap_stats->nonskip_count,
heap_stats->alloc_iter_count / heap_stats->alloc_count,
heap_stats->alloc_iter_count % heap_stats->alloc_count * 10000 / heap_stats->alloc_count,
heap_stats->free_iter_count / heap_stats->free_count,
heap_stats->free_iter_count % heap_stats->free_count * 10000 / heap_stats->free_count);
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
} /* jmem_heap_stats_print */
/**
* Initalize heap memory usage statistics account structure
*/
static void
void
jmem_heap_stat_init (void)
{
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
@@ -604,7 +562,7 @@ jmem_heap_stat_init (void)
/**
* Account allocation
*/
static void
void
jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
{
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
@@ -614,7 +572,6 @@ jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
heap_stats->allocated_bytes += aligned_size;
heap_stats->waste_bytes += waste_bytes;
heap_stats->alloc_count++;
if (heap_stats->allocated_bytes > heap_stats->peak_allocated_bytes)
{
@@ -630,7 +587,7 @@ jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
/**
* Account freeing
*/
static void
void
jmem_heap_stat_free (size_t size) /**< Size of freed block */
{
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
@@ -638,48 +595,10 @@ jmem_heap_stat_free (size_t size) /**< Size of freed block */
jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
heap_stats->free_count++;
heap_stats->allocated_bytes -= aligned_size;
heap_stats->waste_bytes -= waste_bytes;
} /* jmem_heap_stat_free */
#if !ENABLED (JERRY_SYSTEM_ALLOCATOR)
/**
* Counts number of skip-aheads during insertion of free block
*/
static void
jmem_heap_stat_skip (void)
{
JERRY_CONTEXT (jmem_heap_stats).skip_count++;
} /* jmem_heap_stat_skip */
/**
* Counts number of times we could not skip ahead during free block insertion
*/
static void
jmem_heap_stat_nonskip (void)
{
JERRY_CONTEXT (jmem_heap_stats).nonskip_count++;
} /* jmem_heap_stat_nonskip */
/**
* Count number of iterations required for allocations
*/
static void
jmem_heap_stat_alloc_iter (void)
{
JERRY_CONTEXT (jmem_heap_stats).alloc_iter_count++;
} /* jmem_heap_stat_alloc_iter */
/**
* Counts number of iterations required for inserting free blocks
*/
static void
jmem_heap_stat_free_iter (void)
{
JERRY_CONTEXT (jmem_heap_stats).free_iter_count++;
} /* jmem_heap_stat_free_iter */
#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */
#endif /* ENABLED (JERRY_MEM_STATS) */
/**
+16 -9
View File
@@ -24,6 +24,10 @@
#define JMEM_ALLOCATOR_INTERNAL
#include "jmem-allocator-internal.h"
#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
#include "ecma-gc.h"
#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
/** \addtogroup mem Memory allocation
* @{
*
@@ -55,7 +59,7 @@ inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
jmem_pools_alloc (size_t size) /**< size of the chunk */
{
#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
ecma_free_unused_memory (JMEM_PRESSURE_LOW);
#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
#if ENABLED (JERRY_CPOINTER_32_BIT)
@@ -70,16 +74,17 @@ jmem_pools_alloc (size_t size) /**< size of the chunk */
const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_p->next_p;
JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JMEM_HEAP_STAT_ALLOC (8);
return (void *) chunk_p;
}
else
{
return (void *) jmem_heap_alloc_block (8);
void *chunk_p = jmem_heap_alloc_block_internal (8);
JMEM_HEAP_STAT_ALLOC (8);
return chunk_p;
}
#if ENABLED (JERRY_CPOINTER_32_BIT)
@@ -92,16 +97,17 @@ jmem_pools_alloc (size_t size) /**< size of the chunk */
const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_p->next_p;
JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
JMEM_HEAP_STAT_ALLOC (16);
return (void *) chunk_p;
}
else
{
return (void *) jmem_heap_alloc_block (16);
void *chunk_p = jmem_heap_alloc_block_internal (16);
JMEM_HEAP_STAT_ALLOC (16);
return chunk_p;
}
#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
} /* jmem_pools_alloc */
@@ -114,6 +120,7 @@ jmem_pools_free (void *chunk_p, /**< pointer to the chunk */
size_t size) /**< size of the chunk */
{
JERRY_ASSERT (chunk_p != NULL);
JMEM_HEAP_STAT_FREE (size);
jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p;
@@ -158,7 +165,7 @@ jmem_pools_collect_empty (void)
jmem_pools_chunk_t *const next_p = chunk_p->next_p;
JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_heap_free_block (chunk_p, 8);
jmem_heap_free_block_internal (chunk_p, 8);
chunk_p = next_p;
}
@@ -172,7 +179,7 @@ jmem_pools_collect_empty (void)
jmem_pools_chunk_t *const next_p = chunk_p->next_p;
JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
jmem_heap_free_block (chunk_p, 16);
jmem_heap_free_block_internal (chunk_p, 16);
chunk_p = next_p;
}
#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
+12 -26
View File
@@ -70,19 +70,21 @@ typedef uint16_t jmem_cpointer_t;
#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
/**
* Severity of a 'try give memory back' request
* Memory usage pressure for reclaiming unused memory.
*
* The request are posted sequentially beginning from
* low to high until enough memory is freed.
* Each failed allocation will try to reclaim memory with increasing pressure,
* until enough memory is freed to fulfill the allocation request.
*
* If not enough memory is freed upon a high request
* If not enough memory is freed and JMEM_PRESSURE_FULL is reached,
* then the engine is shut down with ERR_OUT_OF_MEMORY.
*/
typedef enum
{
JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW, /**< 'low' severity */
JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH, /**< 'high' severity */
} jmem_free_unused_memory_severity_t;
JMEM_PRESSURE_NONE, /**< no memory pressure */
JMEM_PRESSURE_LOW, /**< low memory pressure */
JMEM_PRESSURE_HIGH, /**< high memory pressure */
JMEM_PRESSURE_FULL, /**< memory full */
} jmem_pressure_t;
/**
* Node for free chunk list
@@ -133,15 +135,6 @@ typedef struct
size_t property_bytes; /**< allocated memory for properties */
size_t peak_property_bytes; /**< peak allocated memory for properties */
size_t skip_count; /**< Number of skip-aheads during insertion of free block */
size_t nonskip_count; /**< Number of times we could not skip ahead during
* free block insertion */
size_t alloc_count; /**< number of memory allocations */
size_t free_count; /**< number of memory frees */
size_t alloc_iter_count; /**< Number of iterations required for allocations */
size_t free_iter_count; /**< Number of iterations required for inserting free blocks */
} jmem_heap_stats_t;
void jmem_stats_allocate_byte_code_bytes (size_t property_size);
@@ -154,21 +147,13 @@ void jmem_stats_allocate_property_bytes (size_t property_size);
void jmem_stats_free_property_bytes (size_t property_size);
void jmem_heap_get_stats (jmem_heap_stats_t *);
void jmem_heap_stats_reset_peak (void);
void jmem_heap_stats_print (void);
#endif /* ENABLED (JERRY_MEM_STATS) */
jmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p);
void * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer);
/**
* A free memory callback routine type.
*/
typedef void (*jmem_free_unused_memory_callback_t) (jmem_free_unused_memory_severity_t);
void jmem_register_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback);
void jmem_unregister_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback);
void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity);
/**
* Define a local array variable and allocate memory for the array on the heap.
*
@@ -245,6 +230,7 @@ void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t s
void *jmem_pools_alloc (size_t size);
void jmem_pools_free (void *chunk_p, size_t size);
void jmem_pools_collect_empty (void);
/**
* @}