php内存模型
2022-01-11 18:08 虎背熊腰 阅读(222) 评论(0) 收藏 举报一:内存结构体
struct _zend_mm_heap {
int use_zend_alloc; /* 是否使用zend内存管理器 */
void *(*_malloc)(size_t); /* 内存分配函数*/
void (*_free)(void*); /* 内存释放函数*/
void *(*_realloc)(void*, size_t);
size_t free_bitmap; /* 小块空闲内存标识 */
size_t large_free_bitmap; /* 大块空闲内存标识*/
size_t block_size; /* 一次内存分配的段大小,即ZEND_MM_SEG_SIZE指定的大小,默认为ZEND_MM_SEG_SIZE (256 * 1024)*/
size_t compact_size; /* 压缩操作边界值,为ZEND_MM_COMPACT指定大小,默认为 2 * 1024 * 1024*/
zend_mm_segment *segments_list; /* 段指针列表 */
zend_mm_storage *storage; /* 所调用的存储层 */
size_t real_size; /* 堆的真实大小 */
size_t real_peak; /* 堆真实大小的峰值 */
size_t limit; /* 堆的内存边界 */
size_t size; /* 堆大小 */
size_t peak; /* 堆大小的峰值*/
size_t reserve_size; /* 备用堆大小*/
void *reserve; /* 备用堆 */
int overflow; /* 内存溢出数*/
int internal;
#if ZEND_MM_CACHE
unsigned int cached; /* 已缓存大小 */
zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS]; /* 缓存数组/
#endif
zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2]; /* 小块内存数组,相当索引的角色 */
zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS]; /* 大块内存数组,相当索引的角色 */
zend_mm_free_block *rest_buckets[2]; /* 剩余内存数组*/
};
二: php 内存架构

内存分配简介:
Smal(slot)(size<=3KB):申请内存小于等于3092B(3/4 page_size),内存池提前定义好了30种同等大小的内存(8,16,24,32,…3072),他们分配在不同的page上(不同大小的内存可能会分配在多个连续的page),申请内存时直接在对应page上查找可用位置
Large(page)(3KB<size<=2MB-4KB):申请内存大于3092B(3/4 page_size),小于2044KB(511 page_size),分配若干个page
Huge(chunk)(size>2MB-4K) :申请内存大于2M,直接调用系统分配,分配若干个chunk
二: php内存初始化
main->sapi_startup->php_cgi_startup->php_module_startupzend_startup->start_memory_manager->zend_mm_startup-> zend_mm_startup_ex->zend_mm_init
三:php 内存分配链路图
1: pemalloc->emalloc->_emalloc-> _zend_mm_alloc_int
sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0); memset(sock, 0, sizeof(php_netstream_data_t)); sock->is_blocked = 1; sock->timeout.tv_sec = FG(default_socket_timeout); sock->timeout.tv_usec = 0; sock->socket = socket; 指针不需要类型转换? => gcc 编译器默认行为
static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
zend_mm_free_block *best_fit;
size_t true_size = ZEND_MM_TRUE_SIZE(size);
size_t block_size;
size_t remaining_size;
size_t segment_size;
zend_mm_segment *segment;
int keep_rest = 0;
#ifdef ZEND_SIGNALS
TSRMLS_FETCH();
#endif
HANDLE_BLOCK_INTERRUPTIONS();
if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
size_t index = ZEND_MM_BUCKET_INDEX(true_size);
size_t bitmap;
if (UNEXPECTED(true_size < size)) {
goto out_of_memory;
}
#if ZEND_MM_CACHE
if (EXPECTED(heap->cache[index] != NULL)) {
/* Get block from cache */
#if ZEND_MM_CACHE_STAT
heap->cache_stat[index].count--;
heap->cache_stat[index].hit++;
#endif
best_fit = heap->cache[index];
heap->cache[index] = best_fit->prev_free_block;
heap->cached -= true_size;
ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
HANDLE_UNBLOCK_INTERRUPTIONS();
return ZEND_MM_DATA_OF(best_fit);
}
#if ZEND_MM_CACHE_STAT
heap->cache_stat[index].miss++;
#endif
#endif
bitmap = heap->free_bitmap >> index;
if (bitmap) {
/* Found some "small" free block that can be used */
index += zend_mm_low_bit(bitmap);
best_fit = heap->free_buckets[index*2];
#if ZEND_MM_CACHE_STAT
heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
#endif
goto zend_mm_finished_searching_for_block;
}
}
#if ZEND_MM_CACHE_STAT
heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
#endif
best_fit = zend_mm_search_large_block(heap, true_size);
if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
zend_mm_free_block *p = heap->rest_buckets[0];
size_t best_size = -1;
while (p != ZEND_MM_REST_BUCKET(heap)) {
if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
best_fit = p;
goto zend_mm_finished_searching_for_block;
} else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
best_fit = p;
}
p = p->prev_free_block;
}
}
if (!best_fit) {
if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
/* Make sure we add a memory block which is big enough,
segment must have header "size" and trailer "guard" block */
segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
keep_rest = 1;
} else {
segment_size = heap->block_size;
}
if (segment_size < true_size ||
heap->real_size + segment_size > heap->limit) {
/* Memory limit overflow */
#if ZEND_MM_CACHE
zend_mm_free_cache(heap);
#endif
HANDLE_UNBLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted at %s:%d (tried to allocate %lu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
#else
zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
#endif
}
segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
if (!segment) {
/* Storage manager cannot allocate memory */
#if ZEND_MM_CACHE
zend_mm_free_cache(heap);
#endif
out_of_memory:
HANDLE_UNBLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
zend_mm_safe_error(heap, "Out of memory (allocated %ld) at %s:%d (tried to allocate %lu bytes)", heap->real_size, __zend_filename, __zend_lineno, size);
#else
zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
#endif
return NULL;
}
heap->real_size += segment_size;
if (heap->real_size > heap->real_peak) {
heap->real_peak = heap->real_size;
}
segment->size = segment_size;
segment->next_segment = heap->segments_list;
heap->segments_list = segment;
best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
ZEND_MM_MARK_FIRST_BLOCK(best_fit);
block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
} else {
zend_mm_finished_searching_for_block:
/* remove from free list */
ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
ZEND_MM_CHECK_COOKIE(best_fit);
ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
zend_mm_remove_from_free_list(heap, best_fit);
block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
}
remaining_size = block_size - true_size;
if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
true_size = block_size;
ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
} else {
zend_mm_free_block *new_free_block;
/* prepare new free block */
ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
/* add the new free block to the free list */
if (EXPECTED(!keep_rest)) {
zend_mm_add_to_free_list(heap, new_free_block);
} else {
zend_mm_add_to_rest_list(heap, new_free_block);
}
}
ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
heap->size += true_size;
if (heap->peak < heap->size) {
heap->peak = heap->size;
}
HANDLE_UNBLOCK_INTERRUPTIONS();
return ZEND_MM_DATA_OF(best_fit);
}
浙公网安备 33010602011771号