关于消除垃圾回收机制缺陷的心得
-
使用预定义的本地 roots:
argv[i] for i in [0, argc-1]. *rval. Even argv[-1] to root a conversion of the obj (a.k.a. this) parameter to a different object, or a new object created to replace obj.
-
当你需要的时候定义更多的本地 roots :
初始化额外的JSFunctionSpec成员到你需要的本地 roots ("extra args") 当中, 之后使用 argv[argc], argv[argc+1], 等. (或者只使用 argv[3] 如果你能够确定这个函数只接收三个参数).
N.B.: The nargs member of JSFunctionSpec tells the engine to provide at least that many args, so you can generally hardwire the local root indices (argv[3] rather than argv[argc]). If more args are passed and you don't care (you aren't writing a varargs-style function), you can just overwrite the extra args with the locally rooted jsvals.
-
Root as you go to avoid newborn pigeon-hole problems:
JSString *str1, *str2; /* Bad! */ str1 = JS_ValueToString(cx, argv[0]); if (!str1) return JS_FALSE; str2 = JS_ValueToString(cx, argv[1]); if (!str2) return JS_FALSE; SomethingThatMightCallTheGC(); /* Good! */ str1 = JS_ValueToString(cx, argv[0]); if (!str1) return JS_FALSE; argv[0] = STRING_TO_JSVAL(str1); str2 = JS_ValueToString(cx, argv[1]); if (!str2) return JS_FALSE; argv[1] = STRING_TO_JSVAL(str2); SomethingThatMightCallTheGC();
-
Avoid malloc'ing temporary storage that contains unrooted jsvals:
/* Bad! */ jsint i, len; jsval *vec; JSString *str; JSObject *myArrayObj; len = NumberOfNativeStrings(); vec = JS_malloc(cx, len * sizeof(jsval)); if (!vec) return JS_FALSE; for (i = 0; i < len; i++) { str = JS_NewStringCopyZ(cx, GetNativeString(i)); if (!str) { JS_free(cx, vec); return JS_FALSE; } vec[i] = STRING_TO_JSVAL(str); } myArrayObj = JS_NewArrayObject(cx, len, vec); JS_free(cx, vec); if (!myArrayObj) return JS_FALSE; OtherStuffThatMightGC(); *rval = OBJECT_TO_JSVAL(myArrayObj); /* Good! */ JSObject *myArrayObj; jsint i, len; JSString *str; jsval val; myArrayObj = JS_NewArrayObject(cx, 0, NULL); if (!myArrayObj) return JS_FALSE; *rval = OBJECT_TO_JSVAL(myArrayObj); len = NumberOfNativeStrings(); for (i = 0; i < len; i++) { str = JS_NewStringCopyZ(cx, GetNativeString(i)); if (!str) return JS_FALSE; val = STRING_TO_JSVAL(str); if (!JS_SetElement(cx, myArrayObj, i, &val)) return JS_FALSE; } OtherStuffThatMightGC();
Note that this example also shows tip #4 (root as you go).
-
Important: don't run the GC at arbitrary times. You must run it only when threads that might have JS interpreter code active on their stacks are all stopped at "safe GC points". The easiest way to do this is to use JS_BeginRequest and JS_EndRequest around each thread's largest chunk of JS API usage (say, evaluating a script and converting its result into a string). You can run the GC after some number of scripts, or from a "GC thread" that wakes up periodically, e.g. Beware realtime effects! Just how sensitive are you to latency?
How to Dump the GC Heap
Using these steps you can find all the GC'able items and what they're linked to.
Steps
- Define GC_MARK_DEBUG in the project that builds the SpiderMonkey Files
- Add code similar to the following around your call to JS_GC
extern "C" FILE* js_DumpGCHeap; js_DumpGCHeap = fopen("c:\\jsds-roots.txt", "w"); JS_GC((*i)->jsc); fclose(js_DumpGCHeap); js_DumpGCHeap = NULL;
Interpreting the results
Results will come out like the following:
061f6810 object 06202ED8 Root via global object(Root @ 0x061f6810).
This points that the JSObject (0x061f6810) with private data (0x06202ED8) and class name "Root" is referenced by the global object (cx->globalObject).
提示
- 为了能够过滤结果你必须在jsgc.c中编辑函数gc_dump_thing. 例如:添加以下代码在你的字符串过滤方法之上:
if(flags & GCX_STRING) return;
原始文档信息
- 作者: Robert Ginda
- 贡献者: Alex Mohr
- 最后更新日期: January 3, 2005
- 版权信息: Copyright (C) Robert Ginda