mirror of
https://github.com/golang/go
synced 2024-11-22 22:00:02 -07:00
runtime: simplify MCache
The nlistmin/size thresholds are copied from tcmalloc, but are unnecesary for Go malloc. We do not do explicit frees into MCache. For sparse cases when we do (mainly hashmap), simpler logic will do. R=rsc, dave, iant CC=gobot, golang-dev, r, remyoudompheng https://golang.org/cl/9373043
This commit is contained in:
parent
23dec8d190
commit
c4cfef075e
@ -109,8 +109,6 @@ enum
|
|||||||
MaxSmallSize = 32<<10,
|
MaxSmallSize = 32<<10,
|
||||||
|
|
||||||
FixAllocChunk = 128<<10, // Chunk size for FixAlloc
|
FixAllocChunk = 128<<10, // Chunk size for FixAlloc
|
||||||
MaxMCacheListLen = 256, // Maximum objects on MCacheList
|
|
||||||
MaxMCacheSize = 2<<20, // Maximum bytes in one MCache
|
|
||||||
MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
|
MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
|
||||||
HeapAllocChunk = 1<<20, // Chunk size for heap growth
|
HeapAllocChunk = 1<<20, // Chunk size for heap growth
|
||||||
|
|
||||||
@ -283,13 +281,11 @@ struct MCacheList
|
|||||||
{
|
{
|
||||||
MLink *list;
|
MLink *list;
|
||||||
uint32 nlist;
|
uint32 nlist;
|
||||||
uint32 nlistmin;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MCache
|
struct MCache
|
||||||
{
|
{
|
||||||
MCacheList list[NumSizeClasses];
|
MCacheList list[NumSizeClasses];
|
||||||
uintptr size;
|
|
||||||
intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
|
intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
|
||||||
intptr local_objects; // objects allocated (or freed) from cache since last lock of heap
|
intptr local_objects; // objects allocated (or freed) from cache since last lock of heap
|
||||||
intptr local_alloc; // bytes allocated (or freed) since last lock of heap
|
intptr local_alloc; // bytes allocated (or freed) since last lock of heap
|
||||||
@ -396,7 +392,7 @@ struct MCentral
|
|||||||
|
|
||||||
void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
|
void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
|
||||||
int32 runtime·MCentral_AllocList(MCentral *c, MLink **first);
|
int32 runtime·MCentral_AllocList(MCentral *c, MLink **first);
|
||||||
void runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *first);
|
void runtime·MCentral_FreeList(MCentral *c, MLink *first);
|
||||||
void runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
|
void runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
|
||||||
|
|
||||||
// Main malloc heap.
|
// Main malloc heap.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Per-thread (in Go, per-M) malloc cache for small objects.
|
// Per-P malloc cache for small objects.
|
||||||
//
|
//
|
||||||
// See malloc.h for an overview.
|
// See malloc.h for an overview.
|
||||||
|
|
||||||
@ -14,26 +14,19 @@ void*
|
|||||||
runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
|
runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
|
||||||
{
|
{
|
||||||
MCacheList *l;
|
MCacheList *l;
|
||||||
MLink *first, *v;
|
MLink *v;
|
||||||
int32 n;
|
|
||||||
|
|
||||||
// Allocate from list.
|
// Allocate from list.
|
||||||
l = &c->list[sizeclass];
|
l = &c->list[sizeclass];
|
||||||
if(l->list == nil) {
|
if(l->list == nil) {
|
||||||
// Replenish using central lists.
|
// Replenish using central lists.
|
||||||
n = runtime·MCentral_AllocList(&runtime·mheap->central[sizeclass], &first);
|
l->nlist = runtime·MCentral_AllocList(&runtime·mheap->central[sizeclass], &l->list);
|
||||||
if(n == 0)
|
if(l->list == nil)
|
||||||
runtime·throw("out of memory");
|
runtime·throw("out of memory");
|
||||||
l->list = first;
|
|
||||||
l->nlist = n;
|
|
||||||
c->size += n*size;
|
|
||||||
}
|
}
|
||||||
v = l->list;
|
v = l->list;
|
||||||
l->list = v->next;
|
l->list = v->next;
|
||||||
l->nlist--;
|
l->nlist--;
|
||||||
if(l->nlist < l->nlistmin)
|
|
||||||
l->nlistmin = l->nlist;
|
|
||||||
c->size -= size;
|
|
||||||
|
|
||||||
// v is zeroed except for the link pointer
|
// v is zeroed except for the link pointer
|
||||||
// that we used above; zero that.
|
// that we used above; zero that.
|
||||||
@ -50,7 +43,7 @@ runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
|
|||||||
|
|
||||||
// Take n elements off l and return them to the central free list.
|
// Take n elements off l and return them to the central free list.
|
||||||
static void
|
static void
|
||||||
ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
|
ReleaseN(MCacheList *l, int32 n, int32 sizeclass)
|
||||||
{
|
{
|
||||||
MLink *first, **lp;
|
MLink *first, **lp;
|
||||||
int32 i;
|
int32 i;
|
||||||
@ -63,18 +56,14 @@ ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
|
|||||||
l->list = *lp;
|
l->list = *lp;
|
||||||
*lp = nil;
|
*lp = nil;
|
||||||
l->nlist -= n;
|
l->nlist -= n;
|
||||||
if(l->nlist < l->nlistmin)
|
|
||||||
l->nlistmin = l->nlist;
|
|
||||||
c->size -= n*runtime·class_to_size[sizeclass];
|
|
||||||
|
|
||||||
// Return them to central free list.
|
// Return them to central free list.
|
||||||
runtime·MCentral_FreeList(&runtime·mheap->central[sizeclass], n, first);
|
runtime·MCentral_FreeList(&runtime·mheap->central[sizeclass], first);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
|
runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
|
||||||
{
|
{
|
||||||
int32 i, n;
|
|
||||||
MCacheList *l;
|
MCacheList *l;
|
||||||
MLink *p;
|
MLink *p;
|
||||||
|
|
||||||
@ -84,34 +73,13 @@ runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
|
|||||||
p->next = l->list;
|
p->next = l->list;
|
||||||
l->list = p;
|
l->list = p;
|
||||||
l->nlist++;
|
l->nlist++;
|
||||||
c->size += size;
|
|
||||||
c->local_cachealloc -= size;
|
c->local_cachealloc -= size;
|
||||||
c->local_objects--;
|
c->local_objects--;
|
||||||
|
|
||||||
if(l->nlist >= MaxMCacheListLen) {
|
// We transfer span at a time from MCentral to MCache,
|
||||||
// Release a chunk back.
|
// if we have 2 times more than that, release a half back.
|
||||||
ReleaseN(c, l, l->nlist/2, sizeclass);
|
if(l->nlist >= 2*(runtime·class_to_allocnpages[sizeclass]<<PageShift)/size)
|
||||||
}
|
ReleaseN(l, l->nlist/2, sizeclass);
|
||||||
|
|
||||||
if(c->size >= MaxMCacheSize) {
|
|
||||||
// Scavenge.
|
|
||||||
for(i=0; i<NumSizeClasses; i++) {
|
|
||||||
l = &c->list[i];
|
|
||||||
n = l->nlistmin;
|
|
||||||
|
|
||||||
// n is the minimum number of elements we've seen on
|
|
||||||
// the list since the last scavenge. If n > 0, it means that
|
|
||||||
// we could have gotten by with n fewer elements
|
|
||||||
// without needing to consult the central free list.
|
|
||||||
// Move toward that situation by releasing n/2 of them.
|
|
||||||
if(n > 0) {
|
|
||||||
if(n > 1)
|
|
||||||
n /= 2;
|
|
||||||
ReleaseN(c, l, n, i);
|
|
||||||
}
|
|
||||||
l->nlistmin = l->nlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -122,7 +90,10 @@ runtime·MCache_ReleaseAll(MCache *c)
|
|||||||
|
|
||||||
for(i=0; i<NumSizeClasses; i++) {
|
for(i=0; i<NumSizeClasses; i++) {
|
||||||
l = &c->list[i];
|
l = &c->list[i];
|
||||||
ReleaseN(c, l, l->nlist, i);
|
if(l->list) {
|
||||||
l->nlistmin = 0;
|
runtime·MCentral_FreeList(&runtime·mheap->central[i], l->list);
|
||||||
|
l->list = nil;
|
||||||
|
l->nlist = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,21 +62,16 @@ runtime·MCentral_AllocList(MCentral *c, MLink **pfirst)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free n objects back into the central free list.
|
// Free the list of objects back into the central free list.
|
||||||
void
|
void
|
||||||
runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start)
|
runtime·MCentral_FreeList(MCentral *c, MLink *start)
|
||||||
{
|
{
|
||||||
MLink *v, *next;
|
MLink *next;
|
||||||
|
|
||||||
// Assume next == nil marks end of list.
|
|
||||||
// n and end would be useful if we implemented
|
|
||||||
// the transfer cache optimization in the TODO above.
|
|
||||||
USED(n);
|
|
||||||
|
|
||||||
runtime·lock(c);
|
runtime·lock(c);
|
||||||
for(v=start; v; v=next) {
|
for(; start != nil; start = next) {
|
||||||
next = v->next;
|
next = start->next;
|
||||||
MCentral_Free(c, v);
|
MCentral_Free(c, start);
|
||||||
}
|
}
|
||||||
runtime·unlock(c);
|
runtime·unlock(c);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user