diff --git a/javascript/packages/core/lib/context.ts b/javascript/packages/core/lib/context.ts index d6875f0ffb..fc5d38cb55 100644 --- a/javascript/packages/core/lib/context.ts +++ b/javascript/packages/core/lib/context.ts @@ -306,9 +306,12 @@ export class MetaStringWriter { } reset() { + // Entries push themselves back on the next root's first write, so the + // list must be truncated or it grows by every past root serialization. this.disposeMetaStringBytes.forEach((item) => { item.dynamicWriteStringId = -1; }); + this.disposeMetaStringBytes.length = 0; this.dynamicNameId = 0; } } diff --git a/javascript/test/fory.test.ts b/javascript/test/fory.test.ts index 50b9b51948..7e34231c08 100644 --- a/javascript/test/fory.test.ts +++ b/javascript/test/fory.test.ts @@ -90,4 +90,21 @@ describe("fory", () => { const result = serialize.deserialize(serialize.serialize(input)); expect(result).toEqual(expected ?? input); } + + test("should meta string state not grow across root serializations", () => { + // Meta string owners re-push themselves on every root serialize; if + // reset() does not truncate the dispose list, it grows without bound and + // every reset walks the whole history. + const fory = new Fory({ compatible: false }); + const { serialize } = fory.register( + Type.struct({ namespace: "example", typeName: "Item" }, { a: Type.int32() }), + ); + serialize({ a: 1 }); + const metaStringWriter = (fory as any).writeContext.metaStringWriter; + const baseline = metaStringWriter.disposeMetaStringBytes.length; + for (let i = 0; i < 100; i++) { + serialize({ a: i }); + } + expect(metaStringWriter.disposeMetaStringBytes.length).toBe(baseline); + }); });