diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-02-18 09:50:58 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-02-18 09:50:58 +0100 |
commit | c072558b90f1bbedc2022b0f30c8b1ac4712538e (patch) | |
tree | 67767591619e4bd8111fb05fac185cde94fb7378 /src/pkg/runtime/malloc.goc | |
parent | 5859517b767c99749a45651c15d4bae5520ebae8 (diff) | |
download | golang-upstream/2011.02.15.tar.gz |
Imported Upstream version 2011.02.15upstream/2011.02.15
Diffstat (limited to 'src/pkg/runtime/malloc.goc')
-rw-r--r-- | src/pkg/runtime/malloc.goc | 186 |
1 files changed, 107 insertions, 79 deletions
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc index cc28b943d..70b85d68d 100644 --- a/src/pkg/runtime/malloc.goc +++ b/src/pkg/runtime/malloc.goc @@ -36,14 +36,13 @@ fastrand1(void) // Small objects are allocated from the per-thread cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. void* -runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed) +runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed) { int32 sizeclass, rate; MCache *c; uintptr npages; MSpan *s; void *v; - uint32 *ref; if(runtime·gcwaiting && g != m->g0 && m->locks == 0) runtime·gosched(); @@ -65,12 +64,6 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed) mstats.alloc += size; mstats.total_alloc += size; mstats.by_size[sizeclass].nmalloc++; - - if(!runtime·mlookup(v, nil, nil, nil, &ref)) { - runtime·printf("malloc %D; runtime·mlookup failed\n", (uint64)size); - runtime·throw("malloc runtime·mlookup"); - } - *ref = RefNone | refflag; } else { // TODO(rsc): Report tracebacks for very large allocations. @@ -87,13 +80,14 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed) v = (void*)(s->start << PageShift); // setup for mark sweep - s->gcref0 = RefNone | refflag; - ref = &s->gcref0; + runtime·markspan(v, 0, 0, true); } + if(!(flag & FlagNoGC)) + runtime·markallocated(v, size, (flag&FlagNoPointers) != 0); m->mallocing = 0; - if(!(refflag & RefNoProfiling) && (rate = runtime·MemProfileRate) > 0) { + if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) { if(size >= rate) goto profile; if(m->mcache->next_sample > size) @@ -104,7 +98,7 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed) rate = 0x3fffffff; m->mcache->next_sample = fastrand1() % (2*rate); profile: - *ref |= RefProfiled; + runtime·setblockspecial(v); runtime·MProf_Malloc(v, size); } } @@ -124,33 +118,35 @@ runtime·malloc(uintptr size) void runtime·free(void *v) { - int32 sizeclass, size; + int32 sizeclass; MSpan *s; MCache *c; - uint32 prof, *ref; + uint32 prof; + uintptr size; if(v == nil) return; + + // If you change this also change mgc0.c:/^sweepspan, + // which has a copy of the guts of free. if(m->mallocing) runtime·throw("malloc/free - deadlock"); m->mallocing = 1; - if(!runtime·mlookup(v, nil, nil, &s, &ref)) { + if(!runtime·mlookup(v, nil, nil, &s)) { runtime·printf("free %p: not an allocated block\n", v); runtime·throw("free runtime·mlookup"); } - prof = *ref & RefProfiled; - *ref = RefFree; + prof = runtime·blockspecial(v); // Find size class for v. sizeclass = s->sizeclass; if(sizeclass == 0) { // Large object. - if(prof) - runtime·MProf_Free(v, s->npages<<PageShift); - mstats.alloc -= s->npages<<PageShift; - runtime·memclr(v, s->npages<<PageShift); + size = s->npages<<PageShift; + *(uintptr*)(s->start<<PageShift) = 1; // mark as "needs to be zeroed" + runtime·unmarkspan(v, 1<<PageShift); runtime·MHeap_Free(&runtime·mheap, s, 1); } else { // Small object. @@ -158,19 +154,20 @@ runtime·free(void *v) size = runtime·class_to_size[sizeclass]; if(size > sizeof(uintptr)) ((uintptr*)v)[1] = 1; // mark as "needs to be zeroed" - if(prof) - runtime·MProf_Free(v, size); - mstats.alloc -= size; mstats.by_size[sizeclass].nfree++; runtime·MCache_Free(c, v, sizeclass, size); } + runtime·markfreed(v, size); + mstats.alloc -= size; + if(prof) + runtime·MProf_Free(v, size); m->mallocing = 0; } int32 -runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref) +runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) { - uintptr n, nobj, i; + uintptr n, i; byte *p; MSpan *s; @@ -179,12 +176,11 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref) if(sp) *sp = s; if(s == nil) { + runtime·checkfreed(v, 1); if(base) *base = nil; if(size) *size = 0; - if(ref) - *ref = 0; return 0; } @@ -195,14 +191,11 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref) *base = p; if(size) *size = s->npages<<PageShift; - if(ref) - *ref = &s->gcref0; return 1; } - if((byte*)v >= (byte*)s->gcref) { - // pointers into the gc ref counts - // do not count as pointers. + if((byte*)v >= (byte*)s->limit) { + // pointers past the last block do not count as pointers. return 0; } @@ -213,21 +206,6 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref) if(size) *size = n; - // good for error checking, but expensive - if(0) { - nobj = (s->npages << PageShift) / (n + RefcountOverhead); - if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) { - runtime·printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n", - s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages); - runtime·printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n", - s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift, - (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift)); - runtime·throw("bad gcref"); - } - } - if(ref) - *ref = &s->gcref[i]; - return 1; } @@ -246,14 +224,20 @@ runtime·allocmcache(void) int32 runtime·sizeof_C_MStats = sizeof(MStats); +#define MaxArena32 (2U<<30) + void runtime·mallocinit(void) { byte *p; - uintptr arena_size; + uintptr arena_size, bitmap_size; + extern byte end[]; runtime·InitSizes(); + // Set up the allocation arena, a contiguous area of memory where + // allocated data will be found. The arena begins with a bitmap large + // enough to hold 4 bits per allocated word. if(sizeof(void*) == 8) { // On a 64-bit machine, allocate from a single contiguous reservation. // 16 GB should be big enough for now. @@ -273,19 +257,53 @@ runtime·mallocinit(void) // odds of the conservative garbage collector not collecting memory // because some non-pointer block of memory had a bit pattern // that matched a memory address. + // + // Actually we reserve 17 GB (because the bitmap ends up being 1 GB) + // but it hardly matters: fc is not valid UTF-8 either, and we have to + // allocate 15 GB before we get that far. arena_size = 16LL<<30; - p = runtime·SysReserve((void*)(0x00f8ULL<<32), arena_size); + bitmap_size = arena_size / (sizeof(void*)*8/4); + p = runtime·SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size); if(p == nil) runtime·throw("runtime: cannot reserve arena virtual address space"); - runtime·mheap.arena_start = p; - runtime·mheap.arena_used = p; - runtime·mheap.arena_end = p + arena_size; } else { - // On a 32-bit machine, we'll take what we can get for each allocation - // and maintain arena_start and arena_end as min, max we've seen. - runtime·mheap.arena_start = (byte*)0xffffffff; - runtime·mheap.arena_end = 0; + // On a 32-bit machine, we can't typically get away + // with a giant virtual address space reservation. + // Instead we map the memory information bitmap + // immediately after the data segment, large enough + // to handle another 2GB of mappings (256 MB), + // along with a reservation for another 512 MB of memory. + // When that gets used up, we'll start asking the kernel + // for any memory anywhere and hope it's in the 2GB + // following the bitmap (presumably the executable begins + // near the bottom of memory, so we'll have to use up + // most of memory before the kernel resorts to giving out + // memory before the beginning of the text segment). + // + // Alternatively we could reserve 512 MB bitmap, enough + // for 4GB of mappings, and then accept any memory the + // kernel threw at us, but normally that's a waste of 512 MB + // of address space, which is probably too much in a 32-bit world. + bitmap_size = MaxArena32 / (sizeof(void*)*8/4); + arena_size = 512<<20; + + // SysReserve treats the address we ask for, end, as a hint, + // not as an absolute requirement. If we ask for the end + // of the data segment but the operating system requires + // a little more space before we can start allocating, it will + // give out a slightly higher pointer. That's fine. + // Run with what we get back. + p = runtime·SysReserve(end, bitmap_size + arena_size); + if(p == nil) + runtime·throw("runtime: cannot reserve arena virtual address space"); } + if((uintptr)p & (((uintptr)1<<PageShift)-1)) + runtime·throw("runtime: SysReserve returned unaligned address"); + + runtime·mheap.bitmap = p; + runtime·mheap.arena_start = p + bitmap_size; + runtime·mheap.arena_used = runtime·mheap.arena_start; + runtime·mheap.arena_end = runtime·mheap.arena_start + arena_size; // Initialize the rest of the allocator. runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc); @@ -299,26 +317,41 @@ void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n) { byte *p; - - if(sizeof(void*) == 8) { + + if(n <= h->arena_end - h->arena_used) { // Keep taking from our reservation. - if(h->arena_end - h->arena_used < n) - return nil; p = h->arena_used; runtime·SysMap(p, n); h->arena_used += n; + runtime·MHeap_MapBits(h); return p; - } else { - // Take what we can get from the OS. - p = runtime·SysAlloc(n); - if(p == nil) - return nil; - if(p+n > h->arena_used) - h->arena_used = p+n; - if(p > h->arena_end) - h->arena_end = p; - return p; } + + // On 64-bit, our reservation is all we have. + if(sizeof(void*) == 8) + return nil; + + // On 32-bit, once the reservation is gone we can + // try to get memory at a location chosen by the OS + // and hope that it is in the range we allocated bitmap for. + p = runtime·SysAlloc(n); + if(p == nil) + return nil; + + if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) { + runtime·printf("runtime: memory allocated by OS not in usable range"); + runtime·SysFree(p, n); + return nil; + } + + if(p+n > h->arena_used) { + h->arena_used = p+n; + if(h->arena_used > h->arena_end) + h->arena_end = h->arena_used; + runtime·MHeap_MapBits(h); + } + + return p; } // Runtime stubs. @@ -353,7 +386,6 @@ void* runtime·stackalloc(uint32 n) { void *v; - uint32 *ref; if(m->mallocing || m->gcing || n == FixedStack) { runtime·lock(&stacks); @@ -369,11 +401,7 @@ runtime·stackalloc(uint32 n) runtime·unlock(&stacks); return v; } - v = runtime·mallocgc(n, RefNoProfiling, 0, 0); - if(!runtime·mlookup(v, nil, nil, nil, &ref)) - runtime·throw("stackalloc runtime·mlookup"); - *ref = RefStack; - return v; + return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0); } void @@ -399,7 +427,7 @@ func Free(p *byte) { } func Lookup(p *byte) (base *byte, size uintptr) { - runtime·mlookup(p, &base, &size, nil, nil); + runtime·mlookup(p, &base, &size, nil); } func GC() { @@ -422,7 +450,7 @@ func SetFinalizer(obj Eface, finalizer Eface) { runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string); goto throw; } - if(!runtime·mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) { + if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) { runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n"); goto throw; } |