Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,10 @@ export class PyObject {

maybeThrowError();

return new PyObject(result);
const pyObject = new PyObject(result);
// PyObject_Call returns a new reference. Register it so GC releases it.
refregistry.register(pyObject, result);
return pyObject;
}

/**
Expand Down
30 changes: 29 additions & 1 deletion test/test_with_gc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
import python, { Callback } from "../mod.ts";
import python, { Callback, ProxiedPyObject } from "../mod.ts";
import { assertEquals } from "./asserts.ts";

Deno.test("call results release their Python reference after gc", async () => {
const sys = python.import("sys");
const pyModule = python.runModule(
`
target = object()
def get_target():
return target
`,
"call_result_gc",
);
const target = pyModule.target;
const count = () => sys.getrefcount(target).valueOf() as number;

const baseline = count();
const getTarget = pyModule.get_target[ProxiedPyObject];
const callMany = () => {
const results = [];
for (let i = 0; i < 100; i++) results.push(getTarget.call());
};
callMany();
for (let i = 0; i < 10; i++) {
// @ts-ignore: requires --v8-flags=--expose-gc
gc();
await new Promise((resolve) => setTimeout(resolve, 0));
}

assertEquals(count(), baseline);
});
Deno.test(
"js fns are automaticlly converted to callbacks",
// auto callbacks are just a convience api, but they leak their resources
Expand Down
Loading