Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Page heap. | 5 // Page heap. |
6 // | 6 // |
7 // See malloc.h for overview. | 7 // See malloc.h for overview. |
8 // | 8 // |
9 // When a MSpan is in the heap free list, state == MSpanFree | 9 // When a MSpan is in the heap free list, state == MSpanFree |
10 // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span. | 10 // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span. |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
314 | 314 |
315 // Insert s into appropriate list. | 315 // Insert s into appropriate list. |
316 if(s->npages < nelem(h->free)) | 316 if(s->npages < nelem(h->free)) |
317 runtime·MSpanList_Insert(&h->free[s->npages], s); | 317 runtime·MSpanList_Insert(&h->free[s->npages], s); |
318 else | 318 else |
319 runtime·MSpanList_Insert(&h->large, s); | 319 runtime·MSpanList_Insert(&h->large, s); |
320 | 320 |
321 // TODO(rsc): IncrementalScavenge() to return memory to OS. | 321 // TODO(rsc): IncrementalScavenge() to return memory to OS. |
322 } | 322 } |
323 | 323 |
324 // Release (part of) unused memory to OS. | |
325 // Goroutine created in runtime·schedinit. | |
326 // Loop forever. | |
327 void | |
328 runtime·MHeap_Release() | |
dvyukov
2011/12/03 12:38:09
I think we need a better/longer name. "Release" lo
| |
329 { | |
330 int64 tickPeriod = 10e9; | |
331 float64 cutRatio = 0.1; | |
332 | |
333 MHeap *h; | |
334 MSpan *s, *prev; | |
335 PageID p; | |
336 uintptr target, cut, n; | |
337 uint64 prev_idle, prev_inuse, sz; | |
338 | |
339 h = &runtime·mheap; | |
340 prev_inuse = prev_idle = 0; | |
341 | |
342 for (;;) { | |
343 g->status = Gwaiting; | |
344 g->waitreason = "MHeap_Release pause"; | |
dvyukov
2011/12/03 14:20:43
It is user-visible, please provide an end user und
| |
345 runtime·tsleep(tickPeriod); | |
346 | |
347 runtime·lock(h); | |
348 | |
349 if (runtime·MSpanList_IsEmpty(&h->large)) { | |
dvyukov
2011/12/03 12:38:09
Perhaps straight check (heap_idle < HeapAllocChunk
dvyukov
2011/12/03 12:38:09
Drop excessive curly brackets here and below.
| |
350 goto NextRound; | |
351 } | |
352 // Try to not hurt transient allocations. | |
353 if (mstats.heap_inuse > prev_inuse) { | |
dvyukov
2011/12/03 14:20:43
I think it is a way too restrictive (taking into a
| |
354 // Some more hysteresis control is needed. | |
355 goto NextRound; | |
356 } | |
357 target = cutRatio * (mstats.heap_idle >> PageShift); cut = 0; | |
dvyukov
2011/12/03 12:38:09
one statement per line please
dvyukov
2011/12/03 12:38:09
I think target can be 0, then don't bother doing a
| |
358 | |
359 // Small boost toward heap_idle trend. | |
360 if (mstats.heap_idle > prev_idle) { | |
361 target *= 2; | |
362 } | |
363 else if (mstats.heap_idle < prev_idle) { | |
364 target /= 2; | |
365 } | |
366 | |
367 // Cut until target is overtaken, oldest spans first. | |
368 for (s = &h->large; s->next != &h->large; s = s->next) { | |
dvyukov
2011/12/03 12:38:09
can't we just do something along the lines of
s =
| |
369 } | |
370 for (prev = s->prev; prev->next != &h->large && cut < target; pr ev = prev->prev) { | |
371 s = prev->next; | |
372 | |
373 // Prevent fragmentation. | |
374 if (s->npages < (HeapAllocChunk >> PageShift)) { | |
375 // Won't happen as long as (HeapAllocChunk >> Pa geShift) == MaxMHeapList | |
376 continue; | |
377 } | |
378 cut += s->npages; | |
379 | |
380 sz = s->npages << PageShift; | |
381 runtime·SysFree((void*)(s->start << PageShift), sz); | |
382 mstats.heap_sys -= sz; | |
383 mstats.heap_idle -= sz; | |
384 | |
385 // Make sure MHeap_FreeLocked won't coalesce with unmape d chunks. | |
386 p = s->start; | |
387 if(sizeof(void*) == 8) | |
388 p -= ((uintptr)h->arena_start >> PageShift); | |
389 for(n = 0; n < s->npages; n++) | |
390 h->map[p+n] = nil; | |
391 | |
392 runtime·MSpanList_Remove(s); | |
393 runtime·FixAlloc_Free(&h->spanalloc, s); | |
394 mstats.mspan_inuse = h->spanalloc.inuse; | |
395 mstats.mspan_sys = h->spanalloc.sys; | |
396 } | |
397 NextRound: | |
dvyukov
2011/12/03 14:20:43
Perhaps a user would like to check how it works fo
| |
398 prev_idle = mstats.heap_idle; | |
dvyukov
2011/12/03 12:38:09
identation
| |
399 prev_inuse = mstats.heap_inuse; | |
400 runtime·unlock(h); | |
401 } | |
402 } | |
403 | |
324 // Initialize a new span with the given start and npages. | 404 // Initialize a new span with the given start and npages. |
325 void | 405 void |
326 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) | 406 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) |
327 { | 407 { |
328 span->next = nil; | 408 span->next = nil; |
329 span->prev = nil; | 409 span->prev = nil; |
330 span->start = start; | 410 span->start = start; |
331 span->npages = npages; | 411 span->npages = npages; |
332 span->freelist = nil; | 412 span->freelist = nil; |
333 span->ref = 0; | 413 span->ref = 0; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev); | 448 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev); |
369 runtime·throw("MSpanList_Insert"); | 449 runtime·throw("MSpanList_Insert"); |
370 } | 450 } |
371 span->next = list->next; | 451 span->next = list->next; |
372 span->prev = list; | 452 span->prev = list; |
373 span->next->prev = span; | 453 span->next->prev = span; |
374 span->prev->next = span; | 454 span->prev->next = span; |
375 } | 455 } |
376 | 456 |
377 | 457 |
OLD | NEW |