📄 dlmalloc-2.6.4.c
字号:
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`foot:' | Size of chunk, in bytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The P (PREV_INUSE) bit, stored in the unused low-order bit of the
chunk size (which is always a multiple of two words), is an in-use
bit for the *previous* chunk. If that bit is *clear*, then the
word before the current chunk size contains the previous chunk
size, and can be used to find the front of the previous chunk.
(The very first chunk allocated always has this bit set,
preventing access to non-existent (or non-owned) memory.)
Note that the `foot' of the current chunk is actually represented
as the prev_size of the NEXT chunk. (This makes it easier to
deal with alignments etc).
The two exceptions to all this are
1. The special chunk `top', which doesn't bother using the
trailing size field since there is no
next contiguous chunk that would have to index off it. (After
initialization, `top' is forced to always exist. If it would
become less than MINSIZE bytes long, it is replenished via
malloc_extend_top.)
2. Chunks allocated via mmap, which have the second-lowest-order
bit (IS_MMAPPED) set in their size fields. Because they are
never merged or traversed from any other chunk, they have no
foot size or inuse information.
Available chunks are kept in any of several places (all declared below):
* `av': An array of chunks serving as bin headers for consolidated
chunks. Each bin is doubly linked. The bins are approximately
proportionally (log) spaced. There are a lot of these bins
(128). This may look excessive, but works very well in
practice. All procedures maintain the invariant that no
consolidated chunk physically borders another one. Chunks in
bins are kept in size order, with ties going to the
approximately least recently used chunk.
The chunks in each bin are maintained in decreasing sorted order by
size. This is irrelevant for the small bins, which all contain
the same-sized chunks, but facilitates best-fit allocation for
larger chunks. (These lists are just sequential. Keeping them in
order almost never requires enough traversal to warrant using
fancier ordered data structures.) Chunks of the same size are
linked with the most recently freed at the front, and allocations
are taken from the back. This results in LRU or FIFO allocation
order, which tends to give each chunk an equal opportunity to be
consolidated with adjacent freed chunks, resulting in larger free
chunks and less fragmentation.
* `top': The top-most available chunk (i.e., the one bordering the
end of available memory) is treated specially. It is never
included in any bin, is used only if no other chunk is
available, and is released back to the system if it is very
large (see M_TRIM_THRESHOLD).
* `last_remainder': A bin holding only the remainder of the
most recently split (non-top) chunk. This bin is checked
before other non-fitting chunks, so as to provide better
locality for runs of sequentially allocated chunks.
* Implicitly, through the host system's memory mapping tables.
If supported, requests greater than a threshold are usually
serviced via calls to mmap, and then later released via munmap.
*/
/* sizes, alignments */
#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
#define MINSIZE (sizeof(struct malloc_chunk))
/* conversion from malloc headers to user pointers, and back */
#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
/* pad request bytes into a usable size */
#define request2size(req) \ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
/* Check if m has acceptable alignment */
#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
/*
Physical chunk operations
*/
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1
/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
#define IS_MMAPPED 0x2
/* Bits to mask off when extracting size */
#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
/* Ptr to previous physical malloc_chunk */
#define prev_chunk(p)\ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
/*
Dealing with use bits
*/
/* extract p's inuse bit */
#define inuse(p)\((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
/* extract inuse bit of previous chunk */
#define prev_inuse(p) ((p)->size & PREV_INUSE)
/* check for mmap()'ed chunk */
#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
/* set/clear chunk as in use without otherwise disturbing */
#define set_inuse(p)\((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
#define clear_inuse(p)\((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
#define set_inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
#define clear_inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
/*
Dealing with size fields
*/
/* Get size, ignoring use bits */
#define chunksize(p) ((p)->size & ~(SIZE_BITS))
/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
/* Set size/use ignoring previous bits in header */
#define set_head(p, s) ((p)->size = (s))
/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
/*
Bins
The bins, `av_' are an array of pairs of pointers serving as the
heads of (initially empty) doubly-linked lists of chunks, laid out
in a way so that each pair can be treated as if it were in a
malloc_chunk. (This way, the fd/bk offsets for linking bin heads
and chunks are the same).
Bins for sizes < 512 bytes contain chunks of all the same size, spaced
8 bytes apart. Larger bins are approximately logarithmically
spaced. (See the table below.) The `av_' array is never mentioned
directly in the code, but instead via bin access macros.
Bin layout:
64 bins of size 8
32 bins of size 64
16 bins of size 512
8 bins of size 4096
4 bins of size 32768
2 bins of size 262144
1 bin of size what's left
There is actually a little bit of slop in the numbers in bin_index
for the sake of speed. This makes no difference elsewhere.
The special chunks `top' and `last_remainder' get their own bins,
(this is implemented via yet more trickery with the av_ array),
although `top' is never properly linked to its bin since it is
always handled specially.
*/
#define NAV 128 /* number of bins */
typedef struct malloc_chunk* mbinptr;
/* access macros */
#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
/*
The first 2 bins are never indexed. The corresponding av_ cells are instead
used for bookkeeping. This is not to save space, but to simplify
indexing, maintain locality, and avoid some initialization tests.
*/
#define top (bin_at(0)->fd) /* The topmost chunk */
#define last_remainder (bin_at(1)) /* remainder from last split */
/*
Because top initially points to its own bin with initial
zero size, thus forcing extension on the first malloc request,
we avoid having any special code in malloc to check whether
it even exists yet. But we still need to in malloc_extend_top.
*/
#define initial_top ((mchunkptr)(bin_at(0)))
/* Helper macro to initialize bins */
#define IAV(i) bin_at(i), bin_at(i)
static mbinptr av_[NAV * 2 + 2] = {
0, 0,
IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
};
/* field-extraction macros */
#define first(b) ((b)->fd)
#define last(b) ((b)->bk)
/*
Indexing into bins
*/
#define bin_index(sz) \(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ 126)
/*
bins for chunks < 512 are all spaced 8 bytes apart, and hold
identically sized chunks. This is exploited in malloc.
*/
#define MAX_SMALLBIN 63
#define MAX_SMALLBIN_SIZE 512
#define SMALLBIN_WIDTH 8
#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
/*
Requests are `small' if both the corresponding and the next bin are small
*/
#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
/*
To help compensate for the large number of bins, a one-level index
structure is used for bin-by-bin searching. `binblocks' is a
one-word bitvector recording whether groups of BINBLOCKWIDTH bins
have any (possibly) non-empty bins, so they can be skipped over
all at once during during traversals. The bits are NOT always
cleared as soon as all bins in a block are empty, but instead only
when all are noticed to be empty during traversal in malloc.
*/
#define BINBLOCKWIDTH 4 /* bins per block */
#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
/* bin<->block macros */
#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
/* Other static bookkeeping data */
/* variables holding tunable values */
static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
static unsigned long top_pad = DEFAULT_TOP_PAD;
static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
/* The first value returned from sbrk */
static char* sbrk_base = (char*)(-1);
/* The maximum memory obtained from system via sbrk */
static unsigned long max_sbrked_mem = 0;
/* The maximum via either sbrk or mmap */
static unsigned long max_total_mem = 0;
/* internal working copy of mallinfo */
static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* The total memory obtained from system via sbrk */
#define sbrked_mem (current_mallinfo.arena)
/* Tracking mmaps */
static unsigned int n_mmaps = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -