@@ -81,6 +81,7 @@ package runtime
81
81
82
82
import (
83
83
"runtime/internal/atomic"
84
+ "runtime/internal/math"
84
85
"runtime/internal/sys"
85
86
"unsafe"
86
87
)
@@ -99,8 +100,6 @@ const (
99
100
// have the most objects per span.
100
101
maxObjsPerSpan = pageSize / 8
101
102
102
- mSpanInUse = _MSpanInUse
103
-
104
103
concurrentSweep = _ConcurrentSweep
105
104
106
105
_PageSize = 1 << _PageShift // 8KB
@@ -113,8 +112,7 @@ const (
113
112
_TinySize = 16
114
113
_TinySizeClass = int8 (2 )
115
114
116
- _FixAllocChunk = 16 << 10 // FixAlloc 一个 Chunk 的大小
117
- _MaxMHeapList = 1 << (20 - _PageShift ) // Maximum page length for fixed-size list in MHeap.
115
+ _FixAllocChunk = 16 << 10 // FixAlloc 一个 Chunk 的大小
118
116
119
117
// Per-P, 每个 order 对应栈所分割的缓存大小
120
118
_StackCacheSize = 32 * 1024
@@ -134,7 +132,7 @@ const (
134
132
// amd64, addresses are sign-extended beyond heapAddrBits. On
135
133
// other arches, they are zero-extended.
136
134
//
137
- // On 64-bit platforms, we limit this to 48 bits based on a
135
+ // On most 64-bit platforms, we limit this to 48 bits based on a
138
136
// combination of hardware and OS limitations.
139
137
//
140
138
// amd64 hardware limits addresses to 48 bits, sign-extended
@@ -152,10 +150,9 @@ const (
152
150
// bits, in the range [0, 1<<48).
153
151
//
154
152
// ppc64, mips64, and s390x support arbitrary 64 bit addresses
155
- // in hardware. However, since Go only supports Linux on
156
- // these, we lean on OS limits. Based on Linux's processor.h,
157
- // the user address space is limited as follows on 64-bit
158
- // architectures:
153
+ // in hardware. On Linux, Go leans on stricter OS limits. Based
154
+ // on Linux's processor.h, the user address space is limited as
155
+ // follows on 64-bit architectures:
159
156
//
160
157
// Architecture Name Maximum Value (exclusive)
161
158
// ---------------------------------------------------------------------
@@ -172,13 +169,17 @@ const (
172
169
// exceed Go's 48 bit limit, it's extremely unlikely in
173
170
// practice.
174
171
//
172
+ // On aix/ppc64, the limits is increased to 1<<60 to accept addresses
173
+ // returned by mmap syscall. These are in range:
174
+ // 0x0a00000000000000 - 0x0afffffffffffff
175
+ //
175
176
// On 32-bit platforms, we accept the full 32-bit address
176
177
// space because doing so is cheap.
177
178
// mips32 only has access to the low 2GB of virtual memory, so
178
179
// we further limit it to 31 bits.
179
180
//
180
181
// WebAssembly currently has a limit of 4GB linear memory.
181
- heapAddrBits = (_64bit * (1 - sys .GoarchWasm )) * 48 + (1 - _64bit + sys .GoarchWasm )* (32 - (sys .GoarchMips + sys .GoarchMipsle ))
182
+ heapAddrBits = (_64bit * (1 - sys .GoarchWasm )* ( 1 - sys . GoosAix )) * 48 + (1 - _64bit + sys .GoarchWasm )* (32 - (sys .GoarchMips + sys .GoarchMipsle )) + 60 * sys . GoosAix
182
183
183
184
// maxAlloc is the maximum size of an allocation. On 64-bit,
184
185
// it's theoretically possible to allocate 1<<heapAddrBits bytes. On
@@ -190,16 +191,17 @@ const (
190
191
// The number of bits in a heap address, the size of heap
191
192
// arenas, and the L1 and L2 arena map sizes are related by
192
193
//
193
- // (1 << addrBits ) = arenaBytes * L1entries * L2entries
194
+ // (1 << addr bits ) = arena size * L1 entries * L2 entries
194
195
//
195
196
// Currently, we balance these as follows:
196
197
//
197
- // Platform Addr bits Arena size L1 entries L2 size
198
- // -------------- --------- ---------- ---------- -------
199
- // */64-bit 48 64MB 1 32MB
200
- // windows/64-bit 48 4MB 64 8MB
201
- // */32-bit 32 4MB 1 4KB
202
- // */mips(le) 31 4MB 1 2KB
198
+ // Platform Addr bits Arena size L1 entries L2 entries
199
+ // -------------- --------- ---------- ---------- -----------
200
+ // */64-bit 48 64MB 1 4M (32MB)
201
+ // aix/64-bit 60 256MB 4096 4M (32MB)
202
+ // windows/64-bit 48 4MB 64 1M (8MB)
203
+ // */32-bit 32 4MB 1 1024 (4KB)
204
+ // */mips(le) 31 4MB 1 512 (2KB)
203
205
204
206
// heapArenaBytes 为 heap arena 的大小。
205
207
// heap 由大小为 heapArenaBytes 的映射构成,与 heapArenaBytes 对齐。
@@ -219,7 +221,7 @@ const (
219
221
// logHeapArenaBytes is log_2 of heapArenaBytes. For clarity,
220
222
// prefer using heapArenaBytes where possible (we need the
221
223
// constant to compute some other constants).
222
- logHeapArenaBytes = (6 + 20 )* (_64bit * (1 - sys .GoosWindows )) + (2 + 20 )* (_64bit * sys .GoosWindows ) + (2 + 20 )* (1 - _64bit )
224
+ logHeapArenaBytes = (6 + 20 )* (_64bit * (1 - sys .GoosWindows )* ( 1 - sys . GoosAix )) + (2 + 20 )* (_64bit * sys .GoosWindows ) + (2 + 20 )* (1 - _64bit ) + ( 8 + 20 ) * sys . GoosAix
223
225
224
226
// heapArenaBitmapBytes 为每个 heap arena 的 bitmap 的大小
225
227
heapArenaBitmapBytes = heapArenaBytes / (sys .PtrSize * 8 / 2 )
@@ -239,8 +241,10 @@ const (
239
241
// We use the L1 map on 64-bit Windows because the arena size
240
242
// is small, but the address space is still 48 bits, and
241
243
// there's a high cost to having a large L2.
242
- arenaL1Bits = 6 * (_64bit * sys .GoosWindows )
243
-
244
+ //
245
+ // We use the L1 map on aix/ppc64 to keep the same L2 value
246
+ // as on Linux.
247
+ arenaL1Bits = 6 * (_64bit * sys .GoosWindows ) + 12 * sys .GoosAix
244
248
// arenaL2Bits is the number of bits of the arena number
245
249
// covered by the second level arena index.
246
250
//
@@ -296,27 +300,27 @@ var physPageSize uintptr
296
300
// 注意: sysAlloc 返回的是操作系统排布的内存,但堆分配器可能使用更大的布局。
297
301
// 因此调用方必须谨慎的重排从 sysAlloc 获得的内存。
298
302
//
299
- // SysUnused notifies the operating system that the contents
303
+ // sysUnused notifies the operating system that the contents
300
304
// of the memory region are no longer needed and can be reused
301
305
// for other purposes.
302
- // SysUsed notifies the operating system that the contents
306
+ // sysUsed notifies the operating system that the contents
303
307
// of the memory region are needed again.
304
308
//
305
- // SysFree returns it unconditionally; this is only used if
309
+ // sysFree returns it unconditionally; this is only used if
306
310
// an out-of-memory error has been detected midway through
307
- // an allocation. It is okay if SysFree is a no-op.
311
+ // an allocation. It is okay if sysFree is a no-op.
308
312
//
309
- // SysReserve reserves address space without allocating memory.
313
+ // sysReserve reserves address space without allocating memory.
310
314
// If the pointer passed to it is non-nil, the caller wants the
311
- // reservation there, but SysReserve can still choose another
315
+ // reservation there, but sysReserve can still choose another
312
316
// location if that one is unavailable.
313
- // NOTE: SysReserve returns OS-aligned memory, but the heap allocator
317
+ // NOTE: sysReserve returns OS-aligned memory, but the heap allocator
314
318
// may use larger alignment, so the caller must be careful to realign the
315
319
// memory obtained by sysAlloc.
316
320
//
317
- // SysMap maps previously reserved address space for use.
321
+ // sysMap maps previously reserved address space for use.
318
322
//
319
- // SysFault marks a (already sysAlloc'd) region to fault
323
+ // sysFault marks a (already sysAlloc'd) region to fault
320
324
// if accessed. Used only for debugging the runtime.
321
325
322
326
func mallocinit () {
@@ -379,6 +383,8 @@ func mallocinit() {
379
383
// 但是,在 arm64 中,当使用 4K 大小具有三级的转换缓冲区的页(page)时,用户地址空间
380
384
// 被限制在了 39 bit,因此我们忽略了上面所有的建议并强制分配在 0x40 << 32 上。
381
385
// 在 darwin/arm64 中,地址空间甚至更小。
386
+ // On AIX, mmaps starts at 0x0A00000000000000 for 64-bit.
387
+ // processes.
382
388
//
383
389
// 从 0xc000000000 开始设置保留地址
384
390
// 如果失败,则尝试 0x1c000000000 ~ 0x7fc000000000
@@ -389,6 +395,13 @@ func mallocinit() {
389
395
p = uintptr (i )<< 40 | uintptrMask & (0x0013 << 28 )
390
396
case GOARCH == "arm64" :
391
397
p = uintptr (i )<< 40 | uintptrMask & (0x0040 << 32 )
398
+ case GOOS == "aix" :
399
+ if i == 0 {
400
+ // We don't use addresses directly after 0x0A00000000000000
401
+ // to avoid collisions with others mmaps done by non-go programs.
402
+ continue
403
+ }
404
+ p = uintptr (i )<< 40 | uintptrMask & (0xa0 << 52 )
392
405
case raceenabled :
393
406
// TSAN 运行时需要堆地址在 [0x00c000000000, 0x00e000000000) 范围内
394
407
p = uintptr (i )<< 32 | uintptrMask & (0x00c0 << 32 )
@@ -420,7 +433,7 @@ func mallocinit() {
420
433
// 3. We try to stake out a reasonably large initial
421
434
// heap reservation.
422
435
423
- const arenaMetaSize = unsafe . Sizeof ([ 1 << arenaBits ] heapArena {})
436
+ const arenaMetaSize = ( 1 << arenaBits ) * unsafe . Sizeof ( heapArena {})
424
437
meta := uintptr (sysReserve (nil , arenaMetaSize ))
425
438
if meta != 0 {
426
439
mheap_ .heapArenaAlloc .init (meta , arenaMetaSize )
@@ -603,6 +616,27 @@ mapped:
603
616
}
604
617
}
605
618
619
+ // Add the arena to the arenas list.
620
+ if len (h .allArenas ) == cap (h .allArenas ) {
621
+ size := 2 * uintptr (cap (h .allArenas )) * sys .PtrSize
622
+ if size == 0 {
623
+ size = physPageSize
624
+ }
625
+ newArray := (* notInHeap )(persistentalloc (size , sys .PtrSize , & memstats .gc_sys ))
626
+ if newArray == nil {
627
+ throw ("out of memory allocating allArenas" )
628
+ }
629
+ oldSlice := h .allArenas
630
+ * (* notInHeapSlice )(unsafe .Pointer (& h .allArenas )) = notInHeapSlice {newArray , len (h .allArenas ), int (size / sys .PtrSize )}
631
+ copy (h .allArenas , oldSlice )
632
+ // Do not free the old backing array because
633
+ // there may be concurrent readers. Since we
634
+ // double the array each time, this can lead
635
+ // to at most 2x waste.
636
+ }
637
+ h .allArenas = h .allArenas [:len (h .allArenas )+ 1 ]
638
+ h .allArenas [len (h .allArenas )- 1 ] = ri
639
+
606
640
// Store atomically just in case an object from the
607
641
// new heap arena becomes visible before the heap lock
608
642
// is released (which shouldn't happen, but there's
@@ -695,6 +729,9 @@ func nextFreeFast(s *mspan) gclinkptr {
695
729
// weight allocation. If it is a heavy weight allocation the caller must
696
730
// determine whether a new GC cycle needs to be started or if the GC is active
697
731
// whether this goroutine needs to assist the GC.
732
+ //
733
+ // Must run in a non-preemptible context since otherwise the owner of
734
+ // c could change.
698
735
func (c * mcache ) nextFree (spc spanClass ) (v gclinkptr , s * mspan , shouldhelpgc bool ) {
699
736
s = c .alloc [spc ]
700
737
shouldhelpgc = false
@@ -705,9 +742,7 @@ func (c *mcache) nextFree(spc spanClass) (v gclinkptr, s *mspan, shouldhelpgc bo
705
742
println ("runtime: s.allocCount=" , s .allocCount , "s.nelems=" , s .nelems )
706
743
throw ("s.allocCount != s.nelems && freeIndex == s.nelems" )
707
744
}
708
- systemstack (func () {
709
- c .refill (spc )
710
- })
745
+ c .refill (spc )
711
746
shouldhelpgc = true
712
747
s = c .alloc [spc ]
713
748
@@ -929,7 +964,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
929
964
}
930
965
931
966
if rate := MemProfileRate ; rate > 0 {
932
- if size < uintptr ( rate ) && int32 (size ) < c .next_sample {
967
+ if rate != 1 && int32 (size ) < c .next_sample {
933
968
c .next_sample -= int32 (size )
934
969
} else {
935
970
mp := acquirem ()
@@ -946,7 +981,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
946
981
947
982
if shouldhelpgc {
948
983
if t := (gcTrigger {kind : gcTriggerHeap }); t .test () {
949
- gcStart (gcBackgroundMode , t )
984
+ gcStart (t )
950
985
}
951
986
}
952
987
@@ -993,10 +1028,11 @@ func newarray(typ *_type, n int) unsafe.Pointer {
993
1028
if n == 1 {
994
1029
return mallocgc (typ .size , typ , true )
995
1030
}
996
- if n < 0 || uintptr (n ) > maxSliceCap (typ .size ) {
1031
+ mem , overflow := math .MulUintptr (typ .size , uintptr (n ))
1032
+ if overflow || mem > maxAlloc || n < 0 {
997
1033
panic (plainError ("runtime: allocation size out of range" ))
998
1034
}
999
- return mallocgc (typ . size * uintptr ( n ) , typ , true )
1035
+ return mallocgc (mem , typ , true )
1000
1036
}
1001
1037
1002
1038
//go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray
@@ -1078,6 +1114,15 @@ var globalAlloc struct {
1078
1114
persistentAlloc
1079
1115
}
1080
1116
1117
+ // persistentChunkSize is the number of bytes we allocate when we grow
1118
+ // a persistentAlloc.
1119
+ const persistentChunkSize = 256 << 10
1120
+
1121
+ // persistentChunks is a list of all the persistent chunks we have
1122
+ // allocated. The list is maintained through the first word in the
1123
+ // persistent chunk. This is updated atomically.
1124
+ var persistentChunks * notInHeap
1125
+
1081
1126
// sysAlloc 的一层封装,能够分配小的 chunk
1082
1127
// 没有释放操作
1083
1128
// 用于 函数、类型、调试相关的持久型数据分配。
@@ -1097,7 +1142,6 @@ func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
1097
1142
//go:systemstack
1098
1143
func persistentalloc1 (size , align uintptr , sysStat * uint64 ) * notInHeap {
1099
1144
const (
1100
- chunk = 256 << 10
1101
1145
maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
1102
1146
)
1103
1147
@@ -1135,15 +1179,24 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) *notInHeap {
1135
1179
}
1136
1180
// 四舍五入 off 到 align 的倍数
1137
1181
persistent .off = round (persistent .off , align )
1138
- if persistent .off + size > chunk || persistent .base == nil {
1139
- persistent .base = (* notInHeap )(sysAlloc (chunk , & memstats .other_sys ))
1182
+ if persistent .off + size > persistentChunkSize || persistent .base == nil {
1183
+ persistent .base = (* notInHeap )(sysAlloc (persistentChunkSize , & memstats .other_sys ))
1140
1184
if persistent .base == nil {
1141
1185
if persistent == & globalAlloc .persistentAlloc {
1142
1186
unlock (& globalAlloc .mutex )
1143
1187
}
1144
1188
throw ("runtime: cannot allocate memory" )
1145
1189
}
1146
- persistent .off = 0
1190
+
1191
+ // Add the new chunk to the persistentChunks list.
1192
+ for {
1193
+ chunks := uintptr (unsafe .Pointer (persistentChunks ))
1194
+ * (* uintptr )(unsafe .Pointer (persistent .base )) = chunks
1195
+ if atomic .Casuintptr ((* uintptr )(unsafe .Pointer (& persistentChunks )), chunks , uintptr (unsafe .Pointer (persistent .base ))) {
1196
+ break
1197
+ }
1198
+ }
1199
+ persistent .off = sys .PtrSize
1147
1200
}
1148
1201
p := persistent .base .add (persistent .off )
1149
1202
persistent .off += size
@@ -1159,6 +1212,21 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) *notInHeap {
1159
1212
return p
1160
1213
}
1161
1214
1215
+ // inPersistentAlloc reports whether p points to memory allocated by
1216
+ // persistentalloc. This must be nosplit because it is called by the
1217
+ // cgo checker code, which is called by the write barrier code.
1218
+ //go:nosplit
1219
+ func inPersistentAlloc (p uintptr ) bool {
1220
+ chunk := atomic .Loaduintptr ((* uintptr )(unsafe .Pointer (& persistentChunks )))
1221
+ for chunk != 0 {
1222
+ if p >= chunk && p < chunk + persistentChunkSize {
1223
+ return true
1224
+ }
1225
+ chunk = * (* uintptr )(unsafe .Pointer (chunk ))
1226
+ }
1227
+ return false
1228
+ }
1229
+
1162
1230
// linearAlloc 是一个简单的线性分配器,提前储备了内存的一块区域并在需要时指向该区域。
1163
1231
// 调用方负责加锁。
1164
1232
type linearAlloc struct {
0 commit comments