Use of `unmanaged` on generated classes causing memory leaks
Closed this issue · 3 comments
Hi,
We ran into an issue where the @unmanaged
decorator that is added to certain generated classes causes a memory leak when decoding objects.
Specifically, we have a .proto file like
message NullableDouble {
double value = 1;
bool isNull = 2;
string dummy = 3;
}
which results in Assemblyscript code like
// Code generated by protoc-gen-as. DO NOT EDIT.
// Versions:
// protoc-gen-as v1.2.0
// protoc v3.21.12
import { Writer, Reader, Protobuf } from "as-proto/assembly";
@unmanaged
export class NullableDouble {
static encode(message: NullableDouble, writer: Writer): void {
writer.uint32(9);
writer.double(message.value);
writer.uint32(16);
writer.bool(message.isNull);
}
static decode(reader: Reader, length: i32): NullableDouble {
const end: usize = length < 0 ? reader.end : reader.ptr + length;
const message = new NullableDouble();
while (reader.ptr < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.value = reader.double();
break;
case 2:
message.isNull = reader.bool();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}
value: f64;
isNull: bool;
constructor(value: f64 = 0.0, isNull: bool = false, dummy: string = "") {
this.value = value;
this.isNull = isNull;
}
}
export function encodeNullableDouble(message: NullableDouble): Uint8Array {
return Protobuf.encode(message, NullableDouble.encode);
}
export function decodeNullableDouble(buffer: Uint8Array): NullableDouble {
return Protobuf.decode<NullableDouble>(buffer, NullableDouble.decode);
}
Since the decode
function creates a new instance of NullableDouble
each time (which is an unmanaged class) it appears to lead to constant growth of memory where these instances are not garbage collected. In ours tests, Assemblyscript would keep expanding the memory it had reserved, even while the actual "known" size of the managed memory heap was not increasing.
Did you report that to the AssemblyScript team? My understanding of unmanaged classes is that they are equivalent to structs and that they are stored on a stack instead of the heap, so they don’t have to be garbage collected. I might miss something for sure :)
@piotr-oles I asked on the discord here: https://discord.com/channels/721472913886281818/1086289901315698718
it sounds like it does need to be manually freed to prevent leaks
Ok, thanks for checking that! Then it's a bug on the library side indeed. Feel free to create a PR that removes the generation of unmanaged classes - it should be a pretty simple change.