// Return span from an MCache. void runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s) { MLink *v; int32 cap, n; runtime·lock(c); s->incache = false; // Move any explicitly freed items from the freebuf to the freelist. while((v = s->freebuf) != nil) { s->freebuf = v->next; runtime·markfreed(v); v->next = s->freelist; s->freelist = v; s->ref--; } if(s->ref == 0) { // Free back to heap. Unlikely, but possible. MCentral_ReturnToHeap(c, s); // unlocks c return; } cap = (s->npages << PageShift) / s->elemsize; n = cap - s->ref; if(n > 0) { c->nfree += n; runtime·MSpanList_Remove(s); runtime·MSpanList_Insert(&c->nonempty, s); } runtime·unlock(c); }
void runtime·free ( void *v ) { int32 sizeclass; MSpan *s; MCache *c; uint32 prof; uintptr size; #line 2161 "C:\Go\src\pkg\runtime\malloc.goc" if ( v == nil ) return; #line 2167 "C:\Go\src\pkg\runtime\malloc.goc" if ( m->mallocing ) runtime·throw ( "malloc/free - deadlock" ) ; m->mallocing = 1; #line 2171 "C:\Go\src\pkg\runtime\malloc.goc" if ( !runtime·mlookup ( v , nil , nil , &s ) ) { runtime·printf ( "free %p: not an allocated block\n" , v ) ; runtime·throw ( "free runtime·mlookup" ) ; } prof = runtime·blockspecial ( v ) ; #line 2178 "C:\Go\src\pkg\runtime\malloc.goc" sizeclass = s->sizeclass; c = m->mcache; if ( sizeclass == 0 ) { #line 2182 "C:\Go\src\pkg\runtime\malloc.goc" size = s->npages<<PageShift; * ( uintptr* ) ( s->start<<PageShift ) = 1; #line 2186 "C:\Go\src\pkg\runtime\malloc.goc" runtime·markfreed ( v , size ) ; runtime·unmarkspan ( v , 1<<PageShift ) ; runtime·MHeap_Free ( &runtime·mheap , s , 1 ) ; } else { #line 2191 "C:\Go\src\pkg\runtime\malloc.goc" size = runtime·class_to_size[sizeclass]; if ( size > sizeof ( uintptr ) ) ( ( uintptr* ) v ) [1] = 1; #line 2197 "C:\Go\src\pkg\runtime\malloc.goc" runtime·markfreed ( v , size ) ; c->local_by_size[sizeclass].nfree++; runtime·MCache_Free ( c , v , sizeclass , size ) ; } c->local_alloc -= size; if ( prof ) runtime·MProf_Free ( v , size ) ; m->mallocing = 0; }
// Helper: free one object back into the central free list. // Caller must hold lock on c on entry. Holds lock on exit. static void MCentral_Free(MCentral *c, MLink *v) { MSpan *s; // Find span for v. s = runtime·MHeap_Lookup(&runtime·mheap, v); if(s == nil || s->ref == 0) runtime·throw("invalid free"); if(s->sweepgen != runtime·mheap.sweepgen) runtime·throw("free into unswept span"); // If the span is currently being used unsynchronized by an MCache, // we can't modify the freelist. Add to the freebuf instead. The // items will get moved to the freelist when the span is returned // by the MCache. if(s->incache) { v->next = s->freebuf; s->freebuf = v; return; } // Move span to nonempty if necessary. if(s->freelist == nil) { runtime·MSpanList_Remove(s); runtime·MSpanList_Insert(&c->nonempty, s); } // Add the object to span's free list. runtime·markfreed(v); v->next = s->freelist; s->freelist = v; s->ref--; c->nfree++; // If s is completely freed, return it to the heap. if(s->ref == 0) { MCentral_ReturnToHeap(c, s); // unlocks c runtime·lock(c); } }