Skip to content

Commit

Permalink
runtime, cmd/link: optimize memory allocation on wasm
Browse files Browse the repository at this point in the history
WebAssembly's memory is contiguous. Allocating memory at a high address
also allocates all memory up to that address. This change reduces
the initial memory allocated on wasm from 1GB to 16MB by using multiple
heap arenas and reducing the size of a heap arena.

Fixes #27462.

Change-Id: Ic941e6edcadd411e65a14cb2f9fd6c8eae02fc7a
Reviewed-on: https://go-review.googlesource.com/c/go/+/170950
Run-TryBot: Richard Musiol <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
  • Loading branch information
neelance authored and Richard Musiol committed Apr 16, 2019
1 parent e47090a commit 460f9c6
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 11 deletions.
18 changes: 9 additions & 9 deletions src/cmd/link/internal/wasm/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,18 +297,18 @@ func writeTableSec(ctxt *ld.Link, fns []*wasmFunc) {
}

// writeMemorySec writes the section that declares linear memories. Currently one linear memory is being used.
// Linear memory always starts at address zero. More memory can be requested with the GrowMemory instruction.
func writeMemorySec(ctxt *ld.Link) {
sizeOffset := writeSecHeader(ctxt, sectionMemory)

// Linear memory always starts at address zero.
// The unit of the sizes is "WebAssembly page size", which is 64Ki.
// The minimum is currently set to 1GB, which is a lot.
// More memory can be requested with the grow_memory instruction,
// but this operation currently is rather slow, so we avoid it for now.
// TODO(neelance): Use lower initial memory size.
writeUleb128(ctxt.Out, 1) // number of memories
ctxt.Out.WriteByte(0x00) // no maximum memory size
writeUleb128(ctxt.Out, 1024*16) // minimum (initial) memory size
const (
initialSize = 16 << 20 // 16MB, enough for runtime init without growing
wasmPageSize = 64 << 10 // 64KB
)

writeUleb128(ctxt.Out, 1) // number of memories
ctxt.Out.WriteByte(0x00) // no maximum memory size
writeUleb128(ctxt.Out, initialSize/wasmPageSize) // minimum (initial) memory size

writeSecSize(ctxt, sizeOffset)
}
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/malloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ const (
// logHeapArenaBytes is log_2 of heapArenaBytes. For clarity,
// prefer using heapArenaBytes where possible (we need the
// constant to compute some other constants).
logHeapArenaBytes = (6+20)*(_64bit*(1-sys.GoosWindows)*(1-sys.GoosAix)) + (2+20)*(_64bit*sys.GoosWindows) + (2+20)*(1-_64bit) + (8+20)*sys.GoosAix
logHeapArenaBytes = (6+20)*(_64bit*(1-sys.GoosWindows)*(1-sys.GoosAix)*(1-sys.GoarchWasm)) + (2+20)*(_64bit*sys.GoosWindows) + (2+20)*(1-_64bit) + (8+20)*sys.GoosAix + (2+20)*sys.GoarchWasm

// heapArenaBitmapBytes is the size of each heap arena's bitmap.
heapArenaBitmapBytes = heapArenaBytes / (sys.PtrSize * 8 / 2)
Expand Down Expand Up @@ -394,7 +394,7 @@ func mallocinit() {
_g_.m.mcache = allocmcache()

// Create initial arena growth hints.
if sys.PtrSize == 8 && GOARCH != "wasm" {
if sys.PtrSize == 8 {
// On a 64-bit machine, we pick the following hints
// because:
//
Expand Down

1 comment on commit 460f9c6

@justinclift
Copy link

@justinclift justinclift commented on 460f9c6 Apr 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a data point, initial reports from @Yaoir when testing this earlier today across several mobile devices are positive. No out of memory errors, when previously there were.

Looks really good. 😄

Please sign in to comment.