Subj : Re: Memory management of contexts etc. To : Heath Raftery From : Brendan Eich Date : Tue Sep 23 2003 11:52 am Heath Raftery wrote: >Hi, > >Not long ago folks on this newsgroup saved my sanity but helping me out >in writing a PAC file parser using SpiderMonkey. It is all working great >(woohoo!), but I've got some followup questions about style and proper >contex management. > >My code structure looks like this: > > >main() >{ > daemon(0, 0); > > JSFunction* compiled = compile(arg1) > > for(;;) > { > switch(fork()) > { > case 0: > result = execute(compiled, arg2) > /* act on result */ > break; > } > } > JS_DestroyRuntime(rt); >} > > First, why the asymmetry between compile (which creates both a runtime and a context in it) and main, which destroys the runtime? See js.c for a balanced example (create rt; create cx; do stuff; destroy cx; destroy rt). >JSRuntime *rt; >JSObject *global; >JSClass global_class = >{ > "global", 0, >JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, > JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub >}; > >JSFunction* compile(arg1) >{ > JSContext *cx; > > rt = JS_NewRuntime(1L * 1024L * 1024L); > cx = JS_NewContext(rt, 4L * 1024L); > global = JS_NewObject(cx, &global_class, NULL, NULL); > JS_InitStandardClasses(cx, global); > > JSFunction *compiledFunc = JS_CompileFunction(cx, global, ...); > > //***can't do this here*** > //JS_DestroyContext(cx); > > This will run the GC and collect the function, of course. > return compiledFunc; >} > > So this will return a dangling pointer. >char* execute(JSFunction *compiledScript, const char *arg2) >{ > JSContext *cx; > cx = JS_NewContext(rt, 4L * 1024L); > > Why create a new context for each execution (invocation) of the function? That's needlessly more expensive than the intended use of context, which is one-to-one with thread, usually. > JS_CallFunction(cx, global, compiledScript, 2, args, &rval); > str = JS_ValueToString(cx, rval); > > JS_DestroyContext(cx); > > return JS_GetStringBytes(str); >} > > >Now, note that I can't destroy the context in compile(), because the >function will then fail to run in execute(). Thus, I never actually get >the chance to destroy it! Is this particularly undesirable? > > No, nor is it necessary, obviously ;-). >Is my basic runtime/context use scheme flawed? > Just create rt and cx in main, pass cx around, destroy cx and then rt at the end. There's no rule that says you can't pass cx as a parameter, and in fact it's necessary throughout the API and engine to do so. An alternative that doesn't work for all embeddings would be to use thread-local storage, but that's expensive and obfuscatory. Another possibility, even more expensive, is to create and destroy a context in each function, as you attempted -- but then you'd want to GC-root all otherwise unrooted objects, such as the function object (not the JSFunction *) created by compile. So just pass cx around, after making its creation and destruction symmetric in main. /be .