2010-12-03 05:34:57 +01:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2013-11-06 20:49:01 +01:00
|
|
|
// Per-P malloc cache for small objects.
|
2010-12-03 05:34:57 +01:00
|
|
|
//
|
|
|
|
// See malloc.h for an overview.
|
|
|
|
|
|
|
|
#include "runtime.h"
|
2011-10-27 01:57:58 +02:00
|
|
|
#include "arch.h"
|
2010-12-03 05:34:57 +01:00
|
|
|
#include "malloc.h"
|
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
extern volatile intgo runtime_MemProfileRate
|
|
|
|
__asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
|
|
|
|
|
|
|
|
// dummy MSpan that contains no free objects.
|
|
|
|
static MSpan emptymspan;
|
|
|
|
|
|
|
|
MCache*
|
|
|
|
runtime_allocmcache(void)
|
|
|
|
{
|
|
|
|
intgo rate;
|
|
|
|
MCache *c;
|
|
|
|
int32 i;
|
|
|
|
|
|
|
|
runtime_lock(&runtime_mheap);
|
|
|
|
c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
|
|
|
|
runtime_unlock(&runtime_mheap);
|
|
|
|
runtime_memclr((byte*)c, sizeof(*c));
|
2016-08-30 23:07:47 +02:00
|
|
|
for(i = 0; i < _NumSizeClasses; i++)
|
2014-07-19 10:53:52 +02:00
|
|
|
c->alloc[i] = &emptymspan;
|
|
|
|
|
|
|
|
// Set first allocation sample size.
|
|
|
|
rate = runtime_MemProfileRate;
|
|
|
|
if(rate > 0x3fffffff) // make 2*rate not overflow
|
|
|
|
rate = 0x3fffffff;
|
|
|
|
if(rate != 0)
|
2017-01-14 01:05:42 +01:00
|
|
|
c->next_sample = runtime_fastrand() % (2*rate);
|
2014-07-19 10:53:52 +02:00
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2013-11-06 20:49:01 +01:00
|
|
|
void
|
2014-07-19 10:53:52 +02:00
|
|
|
runtime_freemcache(MCache *c)
|
|
|
|
{
|
|
|
|
runtime_MCache_ReleaseAll(c);
|
|
|
|
runtime_lock(&runtime_mheap);
|
|
|
|
runtime_purgecachedstats(c);
|
|
|
|
runtime_FixAlloc_Free(&runtime_mheap.cachealloc, c);
|
|
|
|
runtime_unlock(&runtime_mheap);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets a span that has a free object in it and assigns it
|
|
|
|
// to be the cached span for the given sizeclass. Returns this span.
|
|
|
|
MSpan*
|
2013-11-06 20:49:01 +01:00
|
|
|
runtime_MCache_Refill(MCache *c, int32 sizeclass)
|
2010-12-03 05:34:57 +01:00
|
|
|
{
|
|
|
|
MCacheList *l;
|
2014-07-19 10:53:52 +02:00
|
|
|
MSpan *s;
|
2010-12-03 05:34:57 +01:00
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
runtime_m()->locks++;
|
|
|
|
// Return the current cached span to the central lists.
|
|
|
|
s = c->alloc[sizeclass];
|
|
|
|
if(s->freelist != nil)
|
|
|
|
runtime_throw("refill on a nonempty span");
|
|
|
|
if(s != &emptymspan)
|
|
|
|
runtime_MCentral_UncacheSpan(&runtime_mheap.central[sizeclass], s);
|
2010-12-03 05:34:57 +01:00
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
// Push any explicitly freed objects to the central lists.
|
|
|
|
// Not required, but it seems like a good time to do it.
|
|
|
|
l = &c->free[sizeclass];
|
|
|
|
if(l->nlist > 0) {
|
|
|
|
runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], l->list);
|
|
|
|
l->list = nil;
|
|
|
|
l->nlist = 0;
|
|
|
|
}
|
2010-12-03 05:34:57 +01:00
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
// Get a new cached span from the central lists.
|
|
|
|
s = runtime_MCentral_CacheSpan(&runtime_mheap.central[sizeclass]);
|
|
|
|
if(s == nil)
|
|
|
|
runtime_throw("out of memory");
|
|
|
|
if(s->freelist == nil) {
|
|
|
|
runtime_printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
|
|
|
|
runtime_throw("empty span");
|
|
|
|
}
|
|
|
|
c->alloc[sizeclass] = s;
|
|
|
|
runtime_m()->locks--;
|
|
|
|
return s;
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-07-19 10:53:52 +02:00
|
|
|
runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size)
|
2010-12-03 05:34:57 +01:00
|
|
|
{
|
|
|
|
MCacheList *l;
|
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
// Put on free list.
|
|
|
|
l = &c->free[sizeclass];
|
2010-12-03 05:34:57 +01:00
|
|
|
p->next = l->list;
|
|
|
|
l->list = p;
|
|
|
|
l->nlist++;
|
|
|
|
|
2014-07-19 10:53:52 +02:00
|
|
|
// We transfer a span at a time from MCentral to MCache,
|
|
|
|
// so we'll do the same in the other direction.
|
|
|
|
if(l->nlist >= (runtime_class_to_allocnpages[sizeclass]<<PageShift)/size) {
|
|
|
|
runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], l->list);
|
|
|
|
l->list = nil;
|
|
|
|
l->nlist = 0;
|
|
|
|
}
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime_MCache_ReleaseAll(MCache *c)
|
|
|
|
{
|
|
|
|
int32 i;
|
2014-07-19 10:53:52 +02:00
|
|
|
MSpan *s;
|
2010-12-03 05:34:57 +01:00
|
|
|
MCacheList *l;
|
|
|
|
|
2016-08-30 23:07:47 +02:00
|
|
|
for(i=0; i<_NumSizeClasses; i++) {
|
2014-07-19 10:53:52 +02:00
|
|
|
s = c->alloc[i];
|
|
|
|
if(s != &emptymspan) {
|
|
|
|
runtime_MCentral_UncacheSpan(&runtime_mheap.central[i], s);
|
|
|
|
c->alloc[i] = &emptymspan;
|
|
|
|
}
|
|
|
|
l = &c->free[i];
|
|
|
|
if(l->nlist > 0) {
|
2013-11-06 20:49:01 +01:00
|
|
|
runtime_MCentral_FreeList(&runtime_mheap.central[i], l->list);
|
|
|
|
l->list = nil;
|
|
|
|
l->nlist = 0;
|
|
|
|
}
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
}
|