Description
This related to my effort to get Go WASM/JS to work with a WebWorker process.
What version of Go are you using (go version
)?
go version devel +0e0cd70ecf Tue Jul 3 04:16:23 2018 +0000 windows/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env
)?
set GOARCH=wasm
set GOBIN=
set GOCACHE=C:\Users\leidegre\AppData\Local\go-build
set GOEXE=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=js
set GOPATH=C:\Users\leidegre\go
set GOPROXY=
set GORACE=
set GOROOT=C:\Users\leidegre\Source\go
set GOTMPDIR=
set GOTOOLDIR=C:\Users\leidegre\Source\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=0
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-fPIC -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\leidegre\AppData\Local\Temp\go-build097448038=/tmp/go-build -gno-record-gcc-switches
set VGOMODROOT=
What did you do?
Trying to pass an nil []byte
slice from a WebWorker process to a web application.
What did you expect to see?
That gigabytes of memory is not allocated.
What did you see instead?
Gigabytes of memory is being allocated on each postMessage
call. This crashes both Chrome and Firefox render process. Haven't tested Edge.
Additional findings
as soon as you console.log or pass a slice through a boundary context, for example postMessage
there's copying associated with the ArrayBuffer. For some reason, the gigabyte ArrayBuffer (Go linear memory) gets copied as well and the heap just explodes typically grinding the web page to a halt or crashing the page.
I was able to work around this issue by passing the slice through this helper function first.
[worker.js]
function slice({ byteOffset, byteLength, buffer }) {
return buffer.slice(byteOffset, byteOffset + byteLength)
}
[worker.go]
var x []byte
x = append(x, 2)
x = append(x, 3)
x = append(x, 5)
y := js.TypedArrayOf(x)
z := global.Call("slice", y)
y.Release()
global.Call("postMessage", z) // from WebWorker postMessage
Note that problem occur even if the slice is empty or nil. If worker.js
, i.e. the WebWorker process does console.log at any time on any object that is backed by the ArrayBuffer you'll see crazy heap explosion and subsequent crashes. Not sure what to do about this but I thought I'd share my findings here. It's mostly a side effect of how things are not something Go/WASM is doing wrong but maybe this can be improved somehow? Passing values between Go/JS seems like a natural thing to do.