1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // See malloc.h for an overview.
9 // The MCentral doesn't actually contain the list of free objects; the MSpan does.
10 // Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
11 // and those that are completely allocated (c->empty).
13 // TODO(rsc): tcmalloc uses a "transfer cache" to split the list
14 // into sections of class_to_transfercount[sizeclass] objects
15 // so that it is faster to move those lists between MCaches and MCentrals.
21 static bool MCentral_Grow(MCentral
*c
);
22 static void* MCentral_Alloc(MCentral
*c
);
23 static void MCentral_Free(MCentral
*c
, void *v
);
25 // Initialize a single central free list.
27 runtime_MCentral_Init(MCentral
*c
, int32 sizeclass
)
30 c
->sizeclass
= sizeclass
;
31 runtime_MSpanList_Init(&c
->nonempty
);
32 runtime_MSpanList_Init(&c
->empty
);
35 // Allocate up to n objects from the central free list.
36 // Return the number of objects allocated.
37 // The objects are linked together by their first words.
38 // On return, *pstart points at the first object and *pend at the last.
40 runtime_MCentral_AllocList(MCentral
*c
, int32 n
, MLink
**pfirst
)
42 MLink
*first
, *last
, *v
;
46 // Replenish central list if empty.
47 if(runtime_MSpanList_IsEmpty(&c
->nonempty
)) {
48 if(!MCentral_Grow(c
)) {
55 // Copy from list, up to n.
56 // First one is guaranteed to work, because we just grew the list.
57 first
= MCentral_Alloc(c
);
59 for(i
=1; i
<n
&& (v
= MCentral_Alloc(c
)) != nil
; i
++) {
71 // Helper: allocate one object from the central free list.
73 MCentral_Alloc(MCentral
*c
)
78 if(runtime_MSpanList_IsEmpty(&c
->nonempty
))
83 s
->freelist
= v
->next
;
84 if(s
->freelist
== nil
) {
85 runtime_MSpanList_Remove(s
);
86 runtime_MSpanList_Insert(&c
->empty
, s
);
91 // Free n objects back into the central free list.
92 // Return the number of objects allocated.
93 // The objects are linked together by their first words.
94 // On return, *pstart points at the first object and *pend at the last.
96 runtime_MCentral_FreeList(MCentral
*c
, int32 n
, MLink
*start
)
100 // Assume next == nil marks end of list.
101 // n and end would be useful if we implemented
102 // the transfer cache optimization in the TODO above.
106 for(v
=start
; v
; v
=next
) {
113 // Helper: free one object back into the central free list.
115 MCentral_Free(MCentral
*c
, void *v
)
122 s
= runtime_MHeap_Lookup(&runtime_mheap
, v
);
123 if(s
== nil
|| s
->ref
== 0)
124 runtime_throw("invalid free");
126 // Move to nonempty if necessary.
127 if(s
->freelist
== nil
) {
128 runtime_MSpanList_Remove(s
);
129 runtime_MSpanList_Insert(&c
->nonempty
, s
);
132 // Add v back to s's free list.
134 p
->next
= s
->freelist
;
138 // If s is completely freed, return it to the heap.
140 size
= runtime_class_to_size
[c
->sizeclass
];
141 runtime_MSpanList_Remove(s
);
142 runtime_unmarkspan((byte
*)(s
->start
<<PageShift
), s
->npages
<<PageShift
);
143 *(uintptr
*)(s
->start
<<PageShift
) = 1; // needs zeroing
145 c
->nfree
-= (s
->npages
<< PageShift
) / size
;
147 runtime_MHeap_Free(&runtime_mheap
, s
, 0);
153 runtime_MGetSizeClassInfo(int32 sizeclass
, uintptr
*sizep
, int32
*npagesp
, int32
*nobj
)
158 npages
= runtime_class_to_allocnpages
[sizeclass
];
159 size
= runtime_class_to_size
[sizeclass
];
162 *nobj
= (npages
<< PageShift
) / size
;
165 // Fetch a new span from the heap and
166 // carve into objects for the free list.
168 MCentral_Grow(MCentral
*c
)
177 runtime_MGetSizeClassInfo(c
->sizeclass
, &size
, &npages
, &n
);
178 s
= runtime_MHeap_Alloc(&runtime_mheap
, npages
, c
->sizeclass
, 0);
180 // TODO(rsc): Log out of memory
185 // Carve span into sequence of blocks.
186 tailp
= &s
->freelist
;
187 p
= (byte
*)(s
->start
<< PageShift
);
188 s
->limit
= p
+ size
*n
;
196 runtime_markspan((byte
*)(s
->start
<<PageShift
), size
, n
, size
*n
< (s
->npages
<<PageShift
));
200 runtime_MSpanList_Insert(&c
->nonempty
, s
);