Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 runtime·FixAlloc_Free(&h->spanalloc, t); | 316 runtime·FixAlloc_Free(&h->spanalloc, t); |
317 mstats.mspan_inuse = h->spanalloc.inuse; | 317 mstats.mspan_inuse = h->spanalloc.inuse; |
318 mstats.mspan_sys = h->spanalloc.sys; | 318 mstats.mspan_sys = h->spanalloc.sys; |
319 } | 319 } |
320 | 320 |
321 // Insert s into appropriate list. | 321 // Insert s into appropriate list. |
322 if(s->npages < nelem(h->free)) | 322 if(s->npages < nelem(h->free)) |
323 runtime·MSpanList_Insert(&h->free[s->npages], s); | 323 runtime·MSpanList_Insert(&h->free[s->npages], s); |
324 else | 324 else |
325 runtime·MSpanList_Insert(&h->large, s); | 325 runtime·MSpanList_Insert(&h->large, s); |
326 | |
327 // TODO(rsc): IncrementalScavenge() to return memory to OS. | |
dvyukov
2012/01/12 14:42:45
remove
| |
328 } | 326 } |
329 | 327 |
330 // Release (part of) unused memory to OS. | 328 // Release (part of) unused memory to OS. |
331 // Goroutine created in runtime·schedinit. | 329 // Goroutine created in runtime·schedinit. |
332 // Loop forever. | 330 // Loop forever. |
333 void | 331 void |
334 runtime·MHeap_Scavenger() | 332 runtime·MHeap_Scavenger(void) |
335 { | 333 { |
336 MHeap *h; | 334 MHeap *h; |
337 MSpan *s, *list; | 335 MSpan *s, *list; |
338 » uint64 tick, grace, now; | 336 » uint64 tick, now, forcegc, limit; |
339 uint32 k, i; | 337 uint32 k, i; |
340 uintptr released, sumreleased; | 338 uintptr released, sumreleased; |
341 byte *env; | 339 byte *env; |
342 bool trace; | 340 bool trace; |
343 Note note; | 341 Note note; |
344 | 342 |
345 » tick = 60e9; | 343 » // If we go two minutes without a garbage collection, force one to run. |
346 » env = runtime·getenv("GOSCVGPERIOD"); | 344 » forcegc = 2*60*1e9; |
347 » if(env != nil) | 345 » // If a span goes unused for 5 minutes after a garbage collection, |
348 » » tick = runtime·atoi(env)*1e9; | 346 » // we hand it back to the operating system. |
349 » grace = 5*tick; | 347 » limit = 5*60*1e9; |
350 » env = runtime·getenv("GOSCVGGRACE"); | 348 » // Make wake-up period small enough for the sampling to be correct. |
351 » if(env != nil) | 349 » tick = forcegc < limit ? forcegc/2 : limit/2; |
352 » » grace = runtime·atoi(env)*1e9; | 350 |
353 | |
354 » k = 0; | |
355 trace = false; | 351 trace = false; |
356 env = runtime·getenv("GOGCTRACE"); | 352 env = runtime·getenv("GOGCTRACE"); |
357 if(env != nil) | 353 if(env != nil) |
358 trace = runtime·atoi(env) > 0; | 354 trace = runtime·atoi(env) > 0; |
359 | 355 |
360 h = &runtime·mheap; | 356 h = &runtime·mheap; |
361 » for(;;) { | 357 » for(k=0;; k++) { |
dvyukov
2012/01/11 17:08:40
perhaps for(k=0;; k++)?
| |
362 » » g->status = Gwaiting; | |
dvyukov
2012/01/11 17:08:40
remove
| |
363 » » g->waitreason = "scavenger goroutine (idle)"; | |
dvyukov
2012/01/11 17:08:40
remove
the goroutine will be in syscall status and
| |
364 runtime·noteclear(¬e); | 358 runtime·noteclear(¬e); |
365 runtime·entersyscall(); | 359 runtime·entersyscall(); |
366 runtime·notetsleep(¬e, tick); | 360 runtime·notetsleep(¬e, tick); |
367 runtime·exitsyscall(); | 361 runtime·exitsyscall(); |
368 | 362 |
369 runtime·lock(h); | 363 runtime·lock(h); |
370 now = runtime·nanotime(); | 364 now = runtime·nanotime(); |
371 » » if(now - mstats.last_gc > 2*tick) { | 365 » » if(now - mstats.last_gc > forcegc) { |
372 runtime·unlock(h); | 366 runtime·unlock(h); |
373 runtime·gc(1); | 367 runtime·gc(1); |
374 runtime·lock(h); | 368 runtime·lock(h); |
375 now = runtime·nanotime(); | 369 now = runtime·nanotime(); |
376 if (trace) | 370 if (trace) |
377 runtime·printf("scvg%d: GC forced\n", k); | 371 runtime·printf("scvg%d: GC forced\n", k); |
378 } | 372 } |
379 sumreleased = 0; | 373 sumreleased = 0; |
380 for(i=0; i < nelem(h->free)+1; i++) { | 374 for(i=0; i < nelem(h->free)+1; i++) { |
381 if(i < nelem(h->free)) | 375 if(i < nelem(h->free)) |
382 list = &h->free[i]; | 376 list = &h->free[i]; |
383 else | 377 else |
384 list = &h->large; | 378 list = &h->large; |
385 if(runtime·MSpanList_IsEmpty(list)) | 379 if(runtime·MSpanList_IsEmpty(list)) |
386 continue; | 380 continue; |
387 for(s=list->next; s != list; s=s->next) { | 381 for(s=list->next; s != list; s=s->next) { |
388 » » » » if(s->state == MSpanFree && s->unusedsince != 0 && (now - s->unusedsince) > grace) { | 382 » » » » if(s->unusedsince != 0 && (now - s->unusedsince) > limit) { |
dvyukov
2012/01/11 17:08:40
You seem to carefully iterate over only free spans
| |
389 released = (s->npages - s->npreleased) < < PageShift; | 383 released = (s->npages - s->npreleased) < < PageShift; |
390 mstats.heap_released += released; | 384 mstats.heap_released += released; |
391 sumreleased += released; | 385 sumreleased += released; |
392 s->npreleased = s->npages; | 386 s->npreleased = s->npages; |
393 runtime·SysUnused((void*)(s->start << Pa geShift), s->npages << PageShift); | 387 runtime·SysUnused((void*)(s->start << Pa geShift), s->npages << PageShift); |
394 } | 388 } |
395 } | 389 } |
396 } | 390 } |
397 runtime·unlock(h); | 391 runtime·unlock(h); |
398 k += 1; | |
dvyukov
2012/01/11 17:08:40
some messages are output before the line and some
| |
399 | 392 |
400 if(trace) { | 393 if(trace) { |
401 if(sumreleased > 0) | 394 if(sumreleased > 0) |
402 » » » » runtime·printf("scvg%d: %D MB released\n", k, su mreleased>>20); | 395 » » » » runtime·printf("scvg%d: %p MB released\n", k, su mreleased>>20); |
403 runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, re leased: %D, consumed: %D (MB)\n", | 396 runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, re leased: %D, consumed: %D (MB)\n", |
404 k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20, | 397 k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20, |
405 mstats.heap_released>>20, (mstats.heap_sys - mst ats.heap_released)>>20); | 398 mstats.heap_released>>20, (mstats.heap_sys - mst ats.heap_released)>>20); |
406 } | 399 } |
407 } | 400 } |
408 } | 401 } |
409 | 402 |
410 // Initialize a new span with the given start and npages. | 403 // Initialize a new span with the given start and npages. |
411 void | 404 void |
412 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) | 405 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
456 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev); | 449 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev); |
457 runtime·throw("MSpanList_Insert"); | 450 runtime·throw("MSpanList_Insert"); |
458 } | 451 } |
459 span->next = list->next; | 452 span->next = list->next; |
460 span->prev = list; | 453 span->prev = list; |
461 span->next->prev = span; | 454 span->next->prev = span; |
462 span->prev->next = span; | 455 span->prev->next = span; |
463 } | 456 } |
464 | 457 |
465 | 458 |
LEFT | RIGHT |