From 397f5cb687f4f31cb0dec85ba5a87237394ca12d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 13 Oct 2017 13:56:06 +0300 Subject: Fixed bug #75368 (mmap/munmap trashing on unlucky allocations) --- Zend/zend_alloc.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'Zend') diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 48def78a41..be41aa3e4a 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -267,6 +267,8 @@ struct _zend_mm_heap { int peak_chunks_count; /* peak number of allocated chunks for current request */ int cached_chunks_count; /* number of cached chunks */ double avg_chunks_count; /* average number of chunks allocated per request */ + int last_chunks_delete_boundary; /* numer of chunks after last deletion */ + int last_chunks_delete_count; /* number of deletion over the last boundary */ #if ZEND_MM_CUSTOM union { struct { @@ -1122,7 +1124,9 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_ chunk->next->prev = chunk->prev; chunk->prev->next = chunk->next; heap->chunks_count--; - if (heap->chunks_count + heap->cached_chunks_count < heap->avg_chunks_count + 0.1) { + if (heap->chunks_count + heap->cached_chunks_count < heap->avg_chunks_count + 0.1 + || (heap->chunks_count == heap->last_chunks_delete_boundary + && heap->last_chunks_delete_count >= 4)) { /* delay deletion */ heap->cached_chunks_count++; chunk->next = heap->cached_chunks; @@ -1131,6 +1135,14 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_ #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size -= ZEND_MM_CHUNK_SIZE; #endif + if (!heap->cached_chunks) { + if (heap->chunks_count != heap->last_chunks_delete_boundary) { + heap->last_chunks_delete_boundary = heap->chunks_count; + heap->last_chunks_delete_count = 0; + } else { + heap->last_chunks_delete_count++; + } + } if (!heap->cached_chunks || chunk->num > heap->cached_chunks->num) { zend_mm_chunk_free(heap, chunk, ZEND_MM_CHUNK_SIZE); } else { @@ -1864,6 +1876,8 @@ static zend_mm_heap *zend_mm_init(void) heap->peak_chunks_count = 1; heap->cached_chunks_count = 0; heap->avg_chunks_count = 1.0; + heap->last_chunks_delete_boundary = 0; + heap->last_chunks_delete_count = 0; #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size = ZEND_MM_CHUNK_SIZE; #endif @@ -2279,6 +2293,8 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent) p->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); heap->chunks_count = 1; heap->peak_chunks_count = 1; + heap->last_chunks_delete_boundary = 0; + heap->last_chunks_delete_count = 0; #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size = ZEND_MM_CHUNK_SIZE; #endif @@ -2811,6 +2827,8 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void heap->peak_chunks_count = 1; heap->cached_chunks_count = 0; heap->avg_chunks_count = 1.0; + heap->last_chunks_delete_boundary = 0; + heap->last_chunks_delete_count = 0; #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size = ZEND_MM_CHUNK_SIZE; #endif -- cgit v1.2.1