📄 elib_malloc.c
字号:
/* Set new endof heap marker and a new heap tail */ eheap_top[sz-1] = 0; tail = (AllocatedBlock*) &eheap_top[sz-MIN_BLOCK_SIZE-1]; tail->hdr = FREE_ABOVE_BIT | MIN_WORD_SIZE; tail->v[0] = 0; tail->v[1] = 0; tail->v[2] = 0; /* Patch old tail with new appended size */ heap_tail->hdr = (heap_tail->hdr & FREE_ABOVE_BIT) | (MIN_WORD_SIZE+1+(sz-MIN_BLOCK_SIZE-1)); deallocate(heap_tail, 0); heap_tail = tail; eheap_size += sz; eheap_top += sz; return 0;}#endif /* ELIB_HEAP_SBRK *//*** Scan heap and check for corrupted heap*/int elib_check_heap(void){ AllocatedBlock* p = heap_head; EWord sz; if (heap_locked) { elib_printf(stderr, "heap is locked no info avaiable\n"); return 0; } while((sz = SIZEOF(p)) != 0) { if (IS_FREE(p)) { if (p->v[sz-1] != sz) { elib_printf(stderr, "panic: heap corrupted\r\n"); ELIB_FAILURE; } p = (AllocatedBlock*) (p->v + sz); if (!IS_FREE_ABOVE(p)) { elib_printf(stderr, "panic: heap corrupted\r\n"); ELIB_FAILURE; } } else p = (AllocatedBlock*) (p->v + sz); } return 1;}/*** Load the byte vector pointed to by v of length vsz** with a heap image** The scale is defined by vsz and the current heap size** free = 0, full = 255** ** */int elib_heap_map(EByte* v, int vsz){ AllocatedBlock* p = heap_head; EWord sz; int gsz = eheap_size / vsz; /* The granuality used */ int fsz = 0; int usz = 0; if (gsz == 0) return -1; /* too good reolution */ while((sz = SIZEOF(p)) != 0) { if (IS_FREE(p)) { fsz += sz; if ((fsz + usz) > gsz) { *v++ = (255*usz)/gsz; fsz -= (gsz - usz); usz = 0; while(fsz >= gsz) { *v++ = 0; fsz -= gsz; } } } else { usz += sz; if ((fsz + usz) > gsz) { *v++ = 255 - (255*fsz)/gsz; usz -= (gsz - fsz); fsz = 0; while(usz >= gsz) { *v++ = 255; usz -= gsz; } } } p = (AllocatedBlock*) (p->v + sz); } return 0;}/*** Generate a histogram of free/allocated blocks** Count granuality of 10 gives** (0-10],(10-100],(100-1000],(1000-10000] ...** (0-2], (2-4], (4-8], (8-16], ....*/static int i_logb(EWord size, int base){ int lg = 0; while(size >= base) { size /= base; lg++; } return lg;}int elib_histo(EWord* vf, EWord* va, int vsz, int base){ AllocatedBlock* p = heap_head; EWord sz; int i; int linear; if ((vsz <= 1) || (vf == 0 && va == 0)) return -1; if (base < 0) { linear = 1; base = -base; } else linear = 0; if (base <= 1) return -1; if (vf != 0) { for (i = 0; i < vsz; i++) vf[i] = 0; } if (va != 0) { for (i = 0; i < vsz; i++) va[i] = 0; } while((sz = SIZEOF(p)) != 0) { if (IS_FREE(p)) { if (vf != 0) { int val; if (linear) val = sz / base; else val = i_logb(sz, base); if (val >= vsz) vf[vsz-1]++; else vf[val]++; } } else { if (va != 0) { int val; if (linear) val = sz / base; else val = i_logb(sz, base); if (val >= vsz) va[vsz-1]++; else va[val]++; } } p = (AllocatedBlock*) (p->v + sz); } return 0;}/*** Fill the info structure with actual values** Total** Allocated** Free** maxMaxFree */void elib_stat(struct elib_stat* info){ EWord blks = 0; EWord sz_free = 0; EWord sz_alloc = 0; EWord sz_max_free = 0; EWord sz_min_used = 0x7fffffff; EWord sz; EWord num_free = 0; AllocatedBlock* p = heap_head; info->mem_total = eheap_size; p = (AllocatedBlock*) (p->v + SIZEOF(p)); while((sz = SIZEOF(p)) != 0) { blks++; if (IS_FREE(p)) { if (sz > sz_max_free) sz_max_free = sz; sz_free += sz; ++num_free; } else { if (sz < sz_min_used) sz_min_used = sz; sz_alloc += sz; } p = (AllocatedBlock*) (p->v + sz); } info->mem_blocks = blks; info->free_blocks = num_free; info->mem_alloc = sz_alloc; info->mem_free = sz_free; info->min_used = sz_min_used; info->max_free = sz_max_free; info->mem_max_alloc = max_allocated; ASSERT(sz_alloc == tot_allocated);}/*** Dump the heap*/void elib_heap_dump(char* label){ AllocatedBlock* p = heap_head; EWord sz; elib_printf(stderr, "HEAP DUMP (%s)\n", label); if (!elib_check_heap()) return; while((sz = SIZEOF(p)) != 0) { if (IS_FREE(p)) { elib_printf(stderr, "%p: FREE, size = %d\n", p, (int) sz); } else { elib_printf(stderr, "%p: USED, size = %d %s\n", p, (int) sz, IS_FREE_ABOVE(p)?"(FREE ABOVE)":""); } p = (AllocatedBlock*) (p->v + sz); }}/*** Scan heaps and count:** free_size, allocated_size, max_free_block*/void elib_statistics(void* to){ struct elib_stat info; EWord frag; if (!elib_check_heap()) return; elib_stat(&info); frag = 1000 - ((1000 * info.max_free) / info.mem_free); elib_printf(to, "Heap Statistics: total(%d), blocks(%d), frag(%d.%d%%)\n", info.mem_total, info.mem_blocks, (int) frag/10, (int) frag % 10); elib_printf(to, " allocated(%d), free(%d), " "free_blocks(%d)\n", info.mem_alloc, info.mem_free,info.free_blocks); elib_printf(to, " max_free(%d), min_used(%d)\n", info.max_free, info.min_used);}/*** Allocate a least nb bytes with alignment a** Algorithm:** 1) Try locate a block which match exacly among the by direct index.** 2) Try using a fix block of greater size** 3) Try locate a block by searching in lists where block sizes** X may vary between 2^i < X <= 2^(i+1)**** Reset memory to zero if clear is true*/static AllocatedBlock* allocate(EWord nb, EWord a, int clear){ FreeBlock* p; EWord nw; if (a == ELIB_ALIGN) { /* * Common case: Called by malloc(), realloc(), calloc(). */ nw = nb < MIN_BYTE_SIZE ? MIN_ALIGN_SIZE : ALIGN_SIZE(nb); if ((p = alloc_block(nw)) == 0) return NULL; } else { /* * Special case: Called by memalign(). */ EWord asz, szp, szq, tmpsz; FreeBlock *q; if ((p = alloc_block((1+MIN_ALIGN_SIZE)*sizeof(EWord)+a-1+nb)) == 0) return NULL; asz = a - ((EWord) ((AllocatedBlock *)p)->v) % a; if (asz != a) { /* Enforce the alignment requirement by cutting of a free block at the beginning of the block. */ if (asz < (1+MIN_ALIGN_SIZE)*sizeof(EWord) && !IS_FREE_ABOVE(p)) { /* Not enough room to cut of a free block; increase align size */ asz += (((1+MIN_ALIGN_SIZE)*sizeof(EWord) + a - 1)/a)*a; } szq = ALIGN_SIZE(asz - sizeof(EWord)); szp = SIZEOF(p) - szq - 1; q = p; p = (FreeBlock*) (((EWord*) q) + szq + 1); p->hdr = FREE_ABOVE_BIT | FREE_BIT | szp; if (IS_FREE_ABOVE(q)) { /* This should not be possible I think, but just in case... */ tmpsz = SIZEOF_ABOVE(q) + 1; szq += tmpsz; q = (FreeBlock*) (((EWord*) q) - tmpsz); unlink_free_block((Block_t *) q); q->hdr = (q->hdr & FREE_ABOVE_BIT) | FREE_BIT | szq; } mark_free(q, szq); link_free_block((Block_t *) q); } /* else already had the correct alignment */ nw = nb < MIN_BYTE_SIZE ? MIN_ALIGN_SIZE : ALIGN_SIZE(nb); } split_block(p, nw, SIZEOF(p)); STAT_ALLOCED_BLOCK(SIZEOF(p)); if (clear) { EWord* pp = ((AllocatedBlock*)p)->v; while(nw--) *pp++ = 0; } return (AllocatedBlock*) p;}/*** Deallocate memory pointed to by p** 1. Merge with block above if this block is free** 2. Merge with block below if this block is free** Link the block to the correct free list**** p points to the block header!***/static void deallocate(AllocatedBlock* p, int stat_count){ FreeBlock* q; EWord szq; EWord szp; szp = SIZEOF(p); if (stat_count) STAT_FREED_BLOCK(SIZEOF(p)); if (IS_FREE_ABOVE(p)) { szq = SIZEOF_ABOVE(p); q = (FreeBlock*) ( ((EWord*) p) - szq - 1); unlink_free_block((Block_t *) q); p = (AllocatedBlock*) q; szp += (szq + 1); } q = (FreeBlock*) (p->v + szp); if (IS_FREE(q)) { szq = SIZEOF(q); unlink_free_block((Block_t *) q); szp += (szq + 1); } else q->hdr |= FREE_ABOVE_BIT; /* The block above p can NEVER be free !!! */ p->hdr = FREE_BIT | szp; p->v[szp-1] = szp; link_free_block((Block_t *) p);}/*** Reallocate memory** If preserve is true then data is moved if neccesary*/static AllocatedBlock* reallocate(AllocatedBlock* p, EWord nb, int preserve){ EWord szp; EWord szq; EWord sz; EWord nw; FreeBlock* q; if (nb < MIN_BYTE_SIZE) nw = MIN_ALIGN_SIZE; else nw = ALIGN_SIZE(nb); sz = szp = SIZEOF(p); STAT_FREED_BLOCK(szp); /* Merge with block below */ q = (FreeBlock*) (p->v + szp); if (IS_FREE(q)) { szq = SIZEOF(q); unlink_free_block((Block_t *) q); szp += (szq + 1); } if (nw <= szp) { split_block((FreeBlock *) p, nw, szp); STAT_ALLOCED_BLOCK(SIZEOF(p)); return p; } else { EWord* dp = p->v; AllocatedBlock* npp; if (IS_FREE_ABOVE(p)) { szq = SIZEOF_ABOVE(p); if (szq + szp + 1 >= nw) { q = (FreeBlock*) (((EWord*) p) - szq - 1); unlink_free_block((Block_t * )q); szp += (szq + 1); p = (AllocatedBlock*) q; if (preserve) { EWord* pp = p->v; while(sz--) *pp++ = *dp++; } split_block((FreeBlock *) p, nw, szp); STAT_ALLOCED_BLOCK(SIZEOF(p)); return p; } } /* * Update p so that allocate() and deallocate() works. * (Note that allocate() may call expand_sbrk(), which in * in turn calls deallocate().) */ p->hdr = (p->hdr & FREE_ABOVE_BIT) | szp; p->v[szp] &= ~FREE_ABOVE_BIT; npp = allocate(nb, ELIB_ALIGN, 0); if(npp == NULL) return NULL; if (preserve) { EWord* pp = npp->v; while(sz--) *pp++ = *dp++; } deallocate(p, 0); return npp; }}/*** What malloc() and friends should do (and return) when the heap is** exhausted. [sverkerw]*/static void* heap_exhausted(void){ /* Choose behaviour */#if 0 /* Crash-and-burn --- leave a usable corpse (hopefully) */ abort();#endif /* The usual ANSI-compliant behaviour */ return NULL;}/*** Allocate size bytes of memory*/void* ELIB_PREFIX(malloc, (size_t nb)){ void *res; AllocatedBlock* p; erts_mtx_lock(&malloc_mutex); if (elib_need_init) locked_elib_init(NULL,(EWord)0); if (nb == 0) res = NULL; else if ((p = allocate(nb, ELIB_ALIGN, 0)) != 0) { ELIB_ALIGN_CHECK(p->v); res = p->v; } else res = heap_exhausted(); erts_mtx_unlock(&malloc_mutex); return res;}void* ELIB_PREFIX(calloc, (size_t nelem, size_t size)){ void *res; int nb; AllocatedBlock* p; erts_mtx_lock(&malloc_mutex); if (elib_need_init) locked_elib_init(NULL,(EWord)0); if ((nb = nelem * size) == 0) res = NULL; else if ((p = allocate(nb, ELIB_ALIGN, 1)) != 0) { ELIB_ALIGN_CHECK(p->v); res = p->v; } else res = heap_exhausted(); erts_mtx_unlock(&malloc_mutex); return res;}/*** Free memory allocated by malloc*/void ELIB_PREFIX(free, (EWord* p)){ erts_mtx_lock(&malloc_mutex); if (elib_need_init) locked_elib_init(NULL,(EWord)0); if (p != 0) deallocate((AllocatedBlock*)(p-1), 1); erts_mtx_unlock(&malloc_mutex);}void ELIB_PREFIX(cfree, (EWord* p)){ ELIB_PREFIX(free, (p));}/*** Realloc the memory allocated in p to nb number of bytes***/void* ELIB_PREFIX(realloc, (EWord* p, size_t nb)){ void *res = NULL; AllocatedBlock* pp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -