Skip to content

Commit c0af058

Browse files
committed
destroy PyProxy object to avoid memory leaks
1 parent 749f529 commit c0af058

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed

src/standalone_fit_worker.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { expose } from 'comlink';
33
import { loadPyodide, version } from 'pyodide';
44
import type { PyodideInterface } from 'pyodide';
55
import { Signal } from './standalone_signal';
6+
import type { PyProxy } from 'pyodide/ffi';
67
const DEBUG = true;
78

89
var pyodide: PyodideInterface;
@@ -11,6 +12,8 @@ declare const REFL1D_WHEEL_FILE: string;
1112
declare const BUMPS_WHEEL_FILE: string;
1213
declare const MOLGROUPS_WHEEL_FILE: string;
1314

15+
type APIResult = PyProxy | number | string | boolean | null | undefined;
16+
1417
async function loadPyodideAndPackages() { // loads pyodide
1518
pyodide = await loadPyodide({
1619
indexURL: `https://cdn.jsdelivr.net/pyodide/v${version}/full/`
@@ -23,8 +26,6 @@ async function loadPyodideAndPackages() { // loads pyodide
2326
import micropip
2427
await micropip.install([
2528
"matplotlib",
26-
"plotly",
27-
"mpld3",
2829
"periodictable",
2930
"blinker",
3031
"dill",
@@ -67,8 +68,12 @@ async function loadPyodideAndPackages() { // loads pyodide
6768
problem = dill.loads(dilled_problem)
6869
api.state.problem.fitProblem = problem
6970
71+
def get_nllf():
72+
return api.state.problem.fitProblem.nllf()
73+
7074
wrapped_api["set_autosave_session_interval"] = expose(set_autosave_session_interval, "set_autosave_session_interval")
7175
wrapped_api["set_problem"] = expose(set_problem, "set_problem")
76+
wrapped_api["get_nllf"] = expose(get_nllf, "get_nllf")
7277
7378
def fit_progress_handler(event):
7479
api.emit("evt_fit_progress", dill.dumps(event))
@@ -161,10 +166,10 @@ export class Server {
161166
let r = await this.nativefs?.syncfs?.();
162167
}
163168

164-
async asyncEmit(signal: string, ...args: unknown[]) {
169+
async asyncEmit(signal: string, ...args: APIResult[]) {
165170
// this is for emit() calls from the python server
166171
const js_args = args.map((arg) => {
167-
return arg?.toJs?.({dict_converter: Object.fromEntries}) ?? arg;
172+
return arg?.toJs?.({dict_converter: Object.fromEntries, create_pyproxies: false}) ?? arg;
168173
});
169174
const handlers = this.handlers[signal] ?? [];
170175
for (let handler of handlers) {
@@ -177,11 +182,12 @@ export class Server {
177182
// (which might be another server)
178183
const api = await pyodideReadyPromise;
179184
const callback = (args[args.length - 1] instanceof Function) ? args.pop() : null;
180-
const result = await api.get(signal)(args);
181-
const jsResult = result?.toJs?.({dict_converter: Object.fromEntries}) ?? result;
185+
const result: PyProxy = await api.get(signal)(args);
186+
const jsResult = result?.toJs?.({dict_converter: Object.fromEntries, create_pyproxies: false}) ?? result;
182187
if (callback !== null) {
183188
await callback(jsResult);
184189
}
190+
result?.destroy?.();
185191
return jsResult;
186192
}
187193

src/standalone_worker.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ export class Server {
252252
signal_handlers = signal_handlers.filter((h) => {
253253
if (h === handler) {
254254
console.log('matching worker handler found, removing: ', handler);
255+
handler?.destroy?.();
255256
return false;
256257
}
257258
return true;
@@ -279,7 +280,7 @@ export class Server {
279280
async asyncEmit(signal: string, ...args: unknown[]) {
280281
// this is for emit() calls from the python server
281282
const js_args = args.map((arg) => {
282-
return arg?.toJs?.({dict_converter: Object.fromEntries}) ?? arg;
283+
return arg?.toJs?.({dict_converter: Object.fromEntries, create_pyproxies: false}) ?? arg;
283284
});
284285
const handlers = this.handlers[signal] ?? [];
285286
for (let handler of handlers) {
@@ -291,11 +292,12 @@ export class Server {
291292
// this is for emit() calls from the client
292293
await this.initialized; // api ready after this...
293294
const callback = (args[args.length - 1] instanceof Function) ? args.pop() : null;
294-
const result = await this.api.get(signal)(args);
295-
const jsResult = result?.toJs?.({dict_converter: Object.fromEntries}) ?? result;
295+
const result: PyProxy | undefined | number | string | null = await this.api.get(signal)(args);
296+
const jsResult = result?.toJs?.({dict_converter: Object.fromEntries, create_pyproxies: false}) ?? result;
296297
if (callback !== null) {
297298
await callback(jsResult);
298299
}
300+
result?.destroy?.();
299301
return jsResult;
300302
}
301303

0 commit comments

Comments
 (0)