@@ -332,37 +332,74 @@ var physPageSize uintptr
332
332
// value is always safe (though potentially less efficient).
333
333
var physHugePageSize uintptr
334
334
335
- // OS-defined helpers:
335
+ // OS memory management abstraction layer
336
336
//
337
- // sysAlloc obtains a large chunk of zeroed memory from the
338
- // operating system, typically on the order of a hundred kilobytes
339
- // or a megabyte.
340
- // NOTE: sysAlloc returns OS-aligned memory, but the heap allocator
341
- // may use larger alignment, so the caller must be careful to realign the
342
- // memory obtained by sysAlloc.
337
+ // Regions of the address space managed by the runtime may be in one of four
338
+ // states at any given time:
339
+ // 1) None - Unreserved and unmapped, the default state of any region.
340
+ // 2) Reserved - Owned by the runtime, but accessing it would cause a fault.
341
+ // Does not count against the process' memory footprint.
342
+ // 3) Prepared - Reserved, intended not to be backed by physical memory (though
343
+ // an OS may implement this lazily). Can transition efficiently to
344
+ // Ready. Accessing memory in such a region is undefined (may
345
+ // fault, may give back unexpected zeroes, etc.).
346
+ // 4) Ready - may be accessed safely.
347
+ //
348
+ // This set of states is more than is strictly necessary to support all the
349
+ // currently supported platforms. One could get by with just None, Reserved, and
350
+ // Ready. However, the Prepared state gives us flexibility for performance
351
+ // purposes. For example, on POSIX-y operating systems, Reserved is usually a
352
+ // private anonymous mmap'd region with PROT_NONE set, and to transition
353
+ // to Ready would require setting PROT_READ|PROT_WRITE. However the
354
+ // underspecification of Prepared lets us use just MADV_FREE to transition from
355
+ // Ready to Prepared. Thus with the Prepared state we can set the permission
356
+ // bits just once early on, we can efficiently tell the OS that it's free to
357
+ // take pages away from us when we don't strictly need them.
358
+ //
359
+ // For each OS there is a common set of helpers defined that transition
360
+ // memory regions between these states. The helpers are as follows:
343
361
//
344
- // sysUnused notifies the operating system that the contents
345
- // of the memory region are no longer needed and can be reused
346
- // for other purposes.
347
- // sysUsed notifies the operating system that the contents
348
- // of the memory region are needed again.
362
+ // sysAlloc transitions an OS-chosen region of memory from None to Ready.
363
+ // More specifically, it obtains a large chunk of zeroed memory from the
364
+ // operating system, typically on the order of a hundred kilobytes
365
+ // or a megabyte. This memory is always immediately available for use.
349
366
//
350
- // sysFree returns it unconditionally; this is only used if
351
- // an out-of-memory error has been detected midway through
352
- // an allocation. It is okay if sysFree is a no-op.
367
+ // sysFree transitions a memory region from any state to None. Therefore, it
368
+ // returns memory unconditionally. It is used if an out-of-memory error has been
369
+ // detected midway through an allocation or to carve out an aligned section of
370
+ // the address space. It is okay if sysFree is a no-op only if sysReserve always
371
+ // returns a memory region aligned to the heap allocator's alignment
372
+ // restrictions.
353
373
//
354
- // sysReserve reserves address space without allocating memory.
374
+ // sysReserve transitions a memory region from None to Reserved. It reserves
375
+ // address space in such a way that it would cause a fatal fault upon access
376
+ // (either via permissions or not committing the memory). Such a reservation is
377
+ // thus never backed by physical memory.
355
378
// If the pointer passed to it is non-nil, the caller wants the
356
379
// reservation there, but sysReserve can still choose another
357
380
// location if that one is unavailable.
358
381
// NOTE: sysReserve returns OS-aligned memory, but the heap allocator
359
382
// may use larger alignment, so the caller must be careful to realign the
360
- // memory obtained by sysAlloc.
383
+ // memory obtained by sysReserve.
384
+ //
385
+ // sysMap transitions a memory region from Reserved to Prepared. It ensures the
386
+ // memory region can be efficiently transitioned to Ready.
361
387
//
362
- // sysMap maps previously reserved address space for use.
388
+ // sysUsed transitions a memory region from Prepared to Ready. It notifies the
389
+ // operating system that the memory region is needed and ensures that the region
390
+ // may be safely accessed. This is typically a no-op on systems that don't have
391
+ // an explicit commit step and hard over-commit limits, but is critical on
392
+ // Windows, for example.
363
393
//
364
- // sysFault marks a (already sysAlloc'd) region to fault
365
- // if accessed. Used only for debugging the runtime.
394
+ // sysUnused transitions a memory region from Ready to Prepared. It notifies the
395
+ // operating system that the physical pages backing this memory region are no
396
+ // longer needed and can be reused for other purposes. The contents of a
397
+ // sysUnused memory region are considered forfeit and the region must not be
398
+ // accessed again until sysUsed is called.
399
+ //
400
+ // sysFault transitions a memory region from Ready or Prepared to Reserved. It
401
+ // marks a region such that it will always fault if accessed. Used only for
402
+ // debugging the runtime.
366
403
367
404
func mallocinit () {
368
405
if class_to_size [_TinySizeClass ] != _TinySize {
@@ -539,6 +576,9 @@ func mallocinit() {
539
576
// heapArenaBytes. sysAlloc returns nil on failure.
540
577
// There is no corresponding free function.
541
578
//
579
+ // sysAlloc returns a memory region in the Prepared state. This region must
580
+ // be transitioned to Ready before use.
581
+ //
542
582
// h must be locked.
543
583
func (h * mheap ) sysAlloc (n uintptr ) (v unsafe.Pointer , size uintptr ) {
544
584
n = round (n , heapArenaBytes )
@@ -580,7 +620,7 @@ func (h *mheap) sysAlloc(n uintptr) (v unsafe.Pointer, size uintptr) {
580
620
// TODO: This would be cleaner if sysReserve could be
581
621
// told to only return the requested address. In
582
622
// particular, this is already how Windows behaves, so
583
- // it would simply things there.
623
+ // it would simplify things there.
584
624
if v != nil {
585
625
sysFree (v , n , nil )
586
626
}
@@ -637,7 +677,7 @@ func (h *mheap) sysAlloc(n uintptr) (v unsafe.Pointer, size uintptr) {
637
677
throw ("misrounded allocation in sysAlloc" )
638
678
}
639
679
640
- // Back the reservation .
680
+ // Transition from Reserved to Prepared .
641
681
sysMap (v , size , & memstats .heap_sys )
642
682
643
683
mapped:
@@ -1288,8 +1328,8 @@ func inPersistentAlloc(p uintptr) bool {
1288
1328
}
1289
1329
1290
1330
// linearAlloc is a simple linear allocator that pre-reserves a region
1291
- // of memory and then maps that region as needed. The caller is
1292
- // responsible for locking.
1331
+ // of memory and then maps that region into the Ready state as needed. The
1332
+ // caller is responsible for locking.
1293
1333
type linearAlloc struct {
1294
1334
next uintptr // next free byte
1295
1335
mapped uintptr // one byte past end of mapped space
@@ -1308,8 +1348,9 @@ func (l *linearAlloc) alloc(size, align uintptr, sysStat *uint64) unsafe.Pointer
1308
1348
}
1309
1349
l .next = p + size
1310
1350
if pEnd := round (l .next - 1 , physPageSize ); pEnd > l .mapped {
1311
- // We need to map more of the reserved space .
1351
+ // Transition from Reserved to Prepared to Ready .
1312
1352
sysMap (unsafe .Pointer (l .mapped ), pEnd - l .mapped , sysStat )
1353
+ sysUsed (unsafe .Pointer (l .mapped ), pEnd - l .mapped )
1313
1354
l .mapped = pEnd
1314
1355
}
1315
1356
return unsafe .Pointer (p )
0 commit comments