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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 h->map[p] = t; | 136 h->map[p] = t; |
137 h->map[p+t->npages-1] = t; | 137 h->map[p+t->npages-1] = t; |
138 *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShi
ft); // copy "needs zeroing" mark | 138 *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShi
ft); // copy "needs zeroing" mark |
139 t->state = MSpanInUse; | 139 t->state = MSpanInUse; |
140 MHeap_FreeLocked(h, t); | 140 MHeap_FreeLocked(h, t); |
141 } | 141 } |
142 | 142 |
143 // Record span info, because gc needs to be | 143 // Record span info, because gc needs to be |
144 // able to map interior pointer to containing span. | 144 // able to map interior pointer to containing span. |
145 s->sizeclass = sizeclass; | 145 s->sizeclass = sizeclass; |
| 146 s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_si
ze[sizeclass]); |
| 147 s->types.compression = MTypes_Empty; |
146 p = s->start; | 148 p = s->start; |
147 if(sizeof(void*) == 8) | 149 if(sizeof(void*) == 8) |
148 p -= ((uintptr)h->arena_start>>PageShift); | 150 p -= ((uintptr)h->arena_start>>PageShift); |
149 for(n=0; n<npage; n++) | 151 for(n=0; n<npage; n++) |
150 h->map[p+n] = s; | 152 h->map[p+n] = s; |
151 return s; | 153 return s; |
152 } | 154 } |
153 | 155 |
154 // Allocate a span of exactly npage pages from the list of large spans. | 156 // Allocate a span of exactly npage pages from the list of large spans. |
155 static MSpan* | 157 static MSpan* |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 MHeap_FreeLocked(h, s); | 282 MHeap_FreeLocked(h, s); |
281 runtime·unlock(h); | 283 runtime·unlock(h); |
282 } | 284 } |
283 | 285 |
284 static void | 286 static void |
285 MHeap_FreeLocked(MHeap *h, MSpan *s) | 287 MHeap_FreeLocked(MHeap *h, MSpan *s) |
286 { | 288 { |
287 uintptr *sp, *tp; | 289 uintptr *sp, *tp; |
288 MSpan *t; | 290 MSpan *t; |
289 PageID p; | 291 PageID p; |
| 292 |
| 293 if(s->types.sysalloc) |
| 294 runtime·settype_sysfree(s); |
| 295 s->types.compression = MTypes_Empty; |
290 | 296 |
291 if(s->state != MSpanInUse || s->ref != 0) { | 297 if(s->state != MSpanInUse || s->ref != 0) { |
292 runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %
d\n", s, s->start<<PageShift, s->state, s->ref); | 298 runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %
d\n", s, s->start<<PageShift, s->state, s->ref); |
293 runtime·throw("MHeap_FreeLocked - invalid free"); | 299 runtime·throw("MHeap_FreeLocked - invalid free"); |
294 } | 300 } |
295 mstats.heap_idle += s->npages<<PageShift; | 301 mstats.heap_idle += s->npages<<PageShift; |
296 s->state = MSpanFree; | 302 s->state = MSpanFree; |
297 s->unusedsince = 0; | 303 s->unusedsince = 0; |
298 s->npreleased = 0; | 304 s->npreleased = 0; |
299 runtime·MSpanList_Remove(s); | 305 runtime·MSpanList_Remove(s); |
(...skipping 30 matching lines...) Expand all Loading... |
330 mstats.mspan_sys = h->spanalloc.sys; | 336 mstats.mspan_sys = h->spanalloc.sys; |
331 } | 337 } |
332 | 338 |
333 // Insert s into appropriate list. | 339 // Insert s into appropriate list. |
334 if(s->npages < nelem(h->free)) | 340 if(s->npages < nelem(h->free)) |
335 runtime·MSpanList_Insert(&h->free[s->npages], s); | 341 runtime·MSpanList_Insert(&h->free[s->npages], s); |
336 else | 342 else |
337 runtime·MSpanList_Insert(&h->large, s); | 343 runtime·MSpanList_Insert(&h->large, s); |
338 } | 344 } |
339 | 345 |
| 346 static void |
| 347 forcegchelper(Note *note) |
| 348 { |
| 349 runtime·gc(1); |
| 350 runtime·notewakeup(note); |
| 351 } |
| 352 |
340 // Release (part of) unused memory to OS. | 353 // Release (part of) unused memory to OS. |
341 // Goroutine created at startup. | 354 // Goroutine created at startup. |
342 // Loop forever. | 355 // Loop forever. |
343 void | 356 void |
344 runtime·MHeap_Scavenger(void) | 357 runtime·MHeap_Scavenger(void) |
345 { | 358 { |
346 MHeap *h; | 359 MHeap *h; |
347 MSpan *s, *list; | 360 MSpan *s, *list; |
348 uint64 tick, now, forcegc, limit; | 361 uint64 tick, now, forcegc, limit; |
349 uint32 k, i; | 362 uint32 k, i; |
350 uintptr released, sumreleased; | 363 uintptr released, sumreleased; |
351 byte *env; | 364 byte *env; |
352 bool trace; | 365 bool trace; |
353 » Note note; | 366 » Note note, *notep; |
354 | 367 |
355 // If we go two minutes without a garbage collection, force one to run. | 368 // If we go two minutes without a garbage collection, force one to run. |
356 forcegc = 2*60*1e9; | 369 forcegc = 2*60*1e9; |
357 // If a span goes unused for 5 minutes after a garbage collection, | 370 // If a span goes unused for 5 minutes after a garbage collection, |
358 // we hand it back to the operating system. | 371 // we hand it back to the operating system. |
359 limit = 5*60*1e9; | 372 limit = 5*60*1e9; |
360 // Make wake-up period small enough for the sampling to be correct. | 373 // Make wake-up period small enough for the sampling to be correct. |
361 if(forcegc < limit) | 374 if(forcegc < limit) |
362 tick = forcegc/2; | 375 tick = forcegc/2; |
363 else | 376 else |
364 tick = limit/2; | 377 tick = limit/2; |
365 | 378 |
366 trace = false; | 379 trace = false; |
367 env = runtime·getenv("GOGCTRACE"); | 380 env = runtime·getenv("GOGCTRACE"); |
368 if(env != nil) | 381 if(env != nil) |
369 trace = runtime·atoi(env) > 0; | 382 trace = runtime·atoi(env) > 0; |
370 | 383 |
371 h = &runtime·mheap; | 384 h = &runtime·mheap; |
372 for(k=0;; k++) { | 385 for(k=0;; k++) { |
373 runtime·noteclear(¬e); | 386 runtime·noteclear(¬e); |
374 runtime·entersyscallblock(); | 387 runtime·entersyscallblock(); |
375 runtime·notetsleep(¬e, tick); | 388 runtime·notetsleep(¬e, tick); |
376 runtime·exitsyscall(); | 389 runtime·exitsyscall(); |
377 | 390 |
378 runtime·lock(h); | 391 runtime·lock(h); |
379 now = runtime·nanotime(); | 392 now = runtime·nanotime(); |
380 if(now - mstats.last_gc > forcegc) { | 393 if(now - mstats.last_gc > forcegc) { |
381 runtime·unlock(h); | 394 runtime·unlock(h); |
382 » » » runtime·gc(1); | 395 » » » // The scavenger can not block other goroutines, |
| 396 » » » // otherwise deadlock detector can fire spuriously. |
| 397 » » » // GC blocks other goroutines via the runtime·worldsema. |
| 398 » » » runtime·noteclear(¬e); |
| 399 » » » notep = ¬e; |
| 400 » » » runtime·newproc1((byte*)forcegchelper, (byte*)¬ep, si
zeof(notep), 0, runtime·MHeap_Scavenger); |
| 401 » » » runtime·entersyscall(); |
| 402 » » » runtime·notesleep(¬e); |
| 403 » » » runtime·exitsyscall(); |
383 runtime·lock(h); | 404 runtime·lock(h); |
384 now = runtime·nanotime(); | 405 now = runtime·nanotime(); |
385 if (trace) | 406 if (trace) |
386 runtime·printf("scvg%d: GC forced\n", k); | 407 runtime·printf("scvg%d: GC forced\n", k); |
387 } | 408 } |
388 sumreleased = 0; | 409 sumreleased = 0; |
389 for(i=0; i < nelem(h->free)+1; i++) { | 410 for(i=0; i < nelem(h->free)+1; i++) { |
390 if(i < nelem(h->free)) | 411 if(i < nelem(h->free)) |
391 list = &h->free[i]; | 412 list = &h->free[i]; |
392 else | 413 else |
(...skipping 26 matching lines...) Expand all Loading... |
419 void | 440 void |
420 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) | 441 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) |
421 { | 442 { |
422 span->next = nil; | 443 span->next = nil; |
423 span->prev = nil; | 444 span->prev = nil; |
424 span->start = start; | 445 span->start = start; |
425 span->npages = npages; | 446 span->npages = npages; |
426 span->freelist = nil; | 447 span->freelist = nil; |
427 span->ref = 0; | 448 span->ref = 0; |
428 span->sizeclass = 0; | 449 span->sizeclass = 0; |
| 450 span->elemsize = 0; |
429 span->state = 0; | 451 span->state = 0; |
430 span->unusedsince = 0; | 452 span->unusedsince = 0; |
431 span->npreleased = 0; | 453 span->npreleased = 0; |
| 454 span->types.compression = MTypes_Empty; |
432 } | 455 } |
433 | 456 |
434 // Initialize an empty doubly-linked list. | 457 // Initialize an empty doubly-linked list. |
435 void | 458 void |
436 runtime·MSpanList_Init(MSpan *list) | 459 runtime·MSpanList_Init(MSpan *list) |
437 { | 460 { |
438 list->state = MSpanListHead; | 461 list->state = MSpanListHead; |
439 list->next = list; | 462 list->next = list; |
440 list->prev = list; | 463 list->prev = list; |
441 } | 464 } |
(...skipping 22 matching lines...) Expand all Loading... |
464 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span-
>next, span->prev); | 487 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span-
>next, span->prev); |
465 runtime·throw("MSpanList_Insert"); | 488 runtime·throw("MSpanList_Insert"); |
466 } | 489 } |
467 span->next = list->next; | 490 span->next = list->next; |
468 span->prev = list; | 491 span->prev = list; |
469 span->next->prev = span; | 492 span->next->prev = span; |
470 span->prev->next = span; | 493 span->prev->next = span; |
471 } | 494 } |
472 | 495 |
473 | 496 |
LEFT | RIGHT |