runtime: out of memory: cannot allocate 4194304-byte block (3997696 in use)
Hello - I've been getting into go-plugin, and while it works well, it seems like there's a memory leak in my application.
I'm not certain how to distill it down to a small example, but this happens consistently, and is easily and quickly reproducible if the wazero runtime has a small memory page limit.
It seems to happen when I call host functions - the error I get is:
runtime: out of memory: cannot allocate 4194304-byte block (3997696 in use)
fatal error: out of memory
goroutine 1 gp=0x4001c0 m=0 mp=0x1f0640 [running]:
runtime.throw({0x57aad, 0xd})
/usr/lib/go/src/runtime/panic.go:1101 +0x3 fp=0x485a40 sp=0x485a18 pc=0x14b60003
runtime.(*mcache).refill(0x210108, 0xa)
/usr/lib/go/src/runtime/mcache.go:185 +0x25 fp=0x485a90 sp=0x485a40 pc=0x110f0025
runtime.(*mcache).nextFree(0x210108, 0xa)
/usr/lib/go/src/runtime/malloc.go:964 +0xa fp=0x485ac8 sp=0x485a90 pc=0x10e4000a
runtime.mallocgcSmallScanNoHeader(0x28, 0x3a880, 0x1)
/usr/lib/go/src/runtime/malloc.go:1366 +0x33 fp=0x485b20 sp=0x485ac8 pc=0x10e70033
runtime.mallocgc(0x28, 0x3a880, 0x1)
/usr/lib/go/src/runtime/malloc.go:1058 +0x10 fp=0x485b58 sp=0x485b20 pc=0x148a0010
runtime.newobject(0x3a880)
/usr/lib/go/src/runtime/malloc.go:1714 +0x4 fp=0x485b80 sp=0x485b58 pc=0x10ee0004
solarlune.com/smallAdventureGame/interop.engine.NodeMove({}, {0x85aa0, 0x1fd1c0}, 0x7f7900)
/home/solarlune/Documents/Projects/Go/games/smallAdventureGame/interop/interop_plugin.pb.go:307 +0x19 fp=0x485be0 sp=0x485b80 pc=0x19040019
solarlune.com/smallAdventureGame/interop.(*engine).NodeMove(0x1fd1c0, {0x85aa0, 0x1fd1c0}, 0x7f7900)
<autogenerated>:1 +0x3 fp=0x485c18 sp=0x485be0 pc=0x19530003
solarlune.com/smallAdventureGame/assets/scripts/utils.GameObjectID.NodeMoveVec(0x6cf, {0x0, 0x0, 0x0})
/home/solarlune/Documents/Projects/Go/games/smallAdventureGame/assets/scripts/utils/plugin.go:141 +0xe fp=0x485ca8 sp=0x485c18 pc=0x197e000e
main.(*Player).OnUpdate(0x43a540)
/home/solarlune/Documents/Projects/Go/games/smallAdventureGame/assets/scripts/player.go:84 +0x47 fp=0x485f38 sp=0x485ca8 pc=0x19fb0047
solarlune.com/smallAdventureGame/assets/scripts/utils.(*goManager).Update(0x1eeb10, {0x85aa0, 0x1fd1c0}, 0x7f3dd0)
/home/solarlune/Documents/Projects/Go/games/smallAdventureGame/assets/scripts/utils/manager.go:29 +0xe fp=0x485f70 sp=0x485f38 pc=0x1973000e
solarlune.com/smallAdventureGame/interop._game_object_manager_update(0x7ec926, 0x3)
/home/solarlune/Documents/Projects/Go/games/smallAdventureGame/interop/interop_plugin.pb.go:61 +0xe fp=0x485fc8 sp=0x485f70 pc=0x18fa000e
game_object_manager_update()
<autogenerated>:1 +0x1 fp=0x485fe0 sp=0x485fc8 pc=0x194e0001
runtime.goexit({})
/usr/lib/go/src/runtime/asm_wasm.s:434 +0x1 fp=0x485fe8 sp=0x485fe0 pc=0x15190001
I'll also get other errors, similarly to do with Malloc, but with others of the host functions.
One of the other sections of goroutine traceback is as follows:
goroutine 6 gp=0x400c40 m=nil [GC worker (idle)]:
runtime.gopark(0x60e50, 0x7cd1a0, 0x1b, 0xa, 0x0)
/usr/lib/go/src/runtime/proc.go:435 +0x22 fp=0x430738 sp=0x430710 pc=0x14b70022
runtime.gcBgMarkWorker(0x4380e0)
/usr/lib/go/src/runtime/mgc.go:1423 +0x1f fp=0x4307d0 sp=0x430738 pc=0x1145001f
runtime.gcBgMarkStartWorkers.gowrap1()
/usr/lib/go/src/runtime/mgc.go:1339 +0x2 fp=0x4307e0 sp=0x4307d0 pc=0x11440002
runtime.goexit({})
/usr/lib/go/src/runtime/asm_wasm.s:434 +0x1 fp=0x4307e8 sp=0x4307e0 pc=0x15190001
created by runtime.gcBgMarkStartWorkers in goroutine 1
/usr/lib/go/src/runtime/mgc.go:1339 +0x28
2025/05/19 17:10:23 wasm error: unreachable
wasm stack trace:
.runtime.abort(i32) i32
.runtime.fatalthrow.func1(i32) i32
.runtime.systemstack(i32) i32
.runtime.fatalthrow(i32) i32
.runtime.throw(i32) i32
.runtime.__mcache_.refill(i32) i32
.runtime.__mcache_.nextFree(i32) i32
.runtime.mallocgcSmallScanNoHeader(i32) i32
.runtime.mallocgc(i32) i32
.runtime.newobject(i32) i32
.solarlune.com_smallAdventureGame_interop.engine.NodeMove(i32) i32
.solarlune.com_smallAdventureGame_interop.__engine_.NodeMove(i32) i32
.solarlune.com_smallAdventureGame_assets_scripts_utils.GameObjectID.NodeMoveVec(i32) i32
.main.__Player_.OnUpdate(i32) i32
.solarlune.com_smallAdventureGame_assets_scripts_utils.__goManager_.Update(i32) i32
.solarlune.com_smallAdventureGame_interop._game_object_manager_update(i32) i32
.game_object_manager_update(i32,i32) i64
fatal error: bad sweepgen in refill
panic during panic
I'm wondering if the garbage collector's running properly? After this, I get module closed messages and out of bounds memory accesses from printing the error from running a function on the WASM plugin:
2025/05/19 17:18:27 wasm error: out of bounds memory access
wasm stack trace:
.github.com_knqyf263_go_plugin_wasm.Malloc(i32) i32
.malloc(i32) i32
EDIT: And I'm building the plugin with standard Go, not Tinygo, with the following command: GOOS=wasip1 GOARCH=wasm go build -o ../scripts.wasm -buildmode=c-shared .
EDIT 2: It seems to happen even if I comment out the host and plugin portions of the functions.
EDIT 3: I'm working with extism now and I think I need to free memory allocated for strings and byte arrays whenever I pass those data types between the host and plugin. I'm wondering if that's what was missing with my usage of go-plugin?