mozilla

Revision 372855 of SpiderMonkey Garbage Collection Tips

  • リビジョンの URL スラグ: SpiderMonkey_Garbage_Collection_Tips
  • リビジョンのタイトル: SpiderMonkey Garbage Collection Tips
  • リビジョンの ID: 372855
  • 作成日:
  • 作成者: yoshitanaka
  • 現行リビジョン いいえ
  • コメント

このリビジョンの内容

 

Tips on avoiding Garbage Collector pitfalls

  1. Use predefined local roots.

    In a JSNative, the elements of argv are roots for the duration of the call. You can assign temporary values to those array elements; in fact it is very good practice to do so. JS_ConvertArguments does this.

    argv{{ mediawiki.external(-1) }} is also a root; it initially roots the obj argument (a.k.a. this) and can be used to root a conversion of obj to a different object, or a new object created to replace obj.

    *rval is also a root.

  2. Define more local roots if you need them.

    Initialize the extra member of JSFunctionSpec to the number of local roots ("extra args") you need, then use argv{{ mediawiki.external('argc') }}argv{{ mediawiki.external('argc+1') }}, etc.

    For JSNatives, the nargs member of JSFunctionSpectells the engine to provide at least that many args, so you can generally hardwire the local root indices (argv{{ mediawiki.external(3) }} rather than argv{{ mediawiki.external('argc') }}). If more arguments are passed and you don't care (you aren't writing a varargs-style function), you can just overwrite the extra arguments with the locally rooted jsvals.

    JSFastNatives cannot ask for extra local roots, and thenargs guarantee does not apply to them.

  3. 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();
  4. Beware {{ Bug(438633) }}. Code that usesJS_CompileScriptJS_CompileFile, orJS_CompileFileHandle must root the new script as described in the JSAPI User Guide under Compiled scripts.

  5. 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 #3 (root as you go).

  6. Follow the request model in multithreaded applications. See JS_THREADSAFE. If you don't follow those rules scrupulously, GC could occur on one thread while another thread is in the JavaScript interpreter or otherwise handling JavaScript pointers. (The GC is not designed to handle that and it will crash.)

  7. Don't run the GC at arbitrary times. You can run the GC after some number of scripts, from a branch callback, or from a "GC thread" that wakes up periodically, for example. 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.

Note: In SpiderMonkey 1.8, these features are being replaced with a new function, JS_DumpHeap.

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).

Hints

  • In order to filter results you must edit the function gc_dump_thing in jsgc.c. As an example, adding the following to the top of the method will filter out strings:
if(flags & GCX_STRING) return;


 

Original Document Information

 

このリビジョンのソースコード

<p>&nbsp;</p>
<h3 id="Tips_on_avoiding_Garbage_Collector_pitfalls" name="Tips_on_avoiding_Garbage_Collector_pitfalls" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 1.142em; font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', Lucida, Arial, Helvetica, sans-serif; ">Tips on avoiding Garbage Collector pitfalls</h3>
<ol style="margin: 0px 0px 1.286em; padding: 0px; list-style: none; ">
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Use predefined local roots.</b></p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">In a&nbsp;<code style="font-style: inherit; "><a href="en/JSNative">JSNative</a></code>, the elements of&nbsp;<code style="font-style: inherit; ">argv</code>&nbsp;are roots for the duration of the call. You can assign temporary values to those array elements; in fact it is very good practice to do so.&nbsp;<code style="font-style: inherit; "><a href="en/JS_ConvertArguments">JS_ConvertArguments</a></code>&nbsp;does this.</p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><code style="font-style: inherit; ">argv{{ mediawiki.external(-1) }}</code>&nbsp;is also a root; it initially roots the&nbsp;<code style="font-style: inherit; ">obj</code>&nbsp;argument (a.k.a.&nbsp;<code style="font-style: inherit; ">this</code>) and can be used to root a conversion of&nbsp;<code style="font-style: inherit; ">obj</code>&nbsp;to a different object, or a new object created to replace&nbsp;<code style="font-style: inherit; ">obj</code>.</p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><code style="font-style: inherit; ">*rval</code>&nbsp;is also a root.</p>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Define more local roots if you need them.</b></p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">Initialize the&nbsp;<code style="font-style: inherit; ">extra</code>&nbsp;member of&nbsp;<code style="font-style: inherit; ">JSFunctionSpec</code>&nbsp;to the number of local roots ("extra args") you need, then use&nbsp;<code style="font-style: inherit; ">argv{{ mediawiki.external('argc') }}</code>,&nbsp;<code style="font-style: inherit; ">argv{{ mediawiki.external('argc+1') }}</code>, etc.</p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">For&nbsp;<code style="font-style: inherit; "><a href="en/JSNative">JSNative</a></code>s, the&nbsp;<code style="font-style: inherit; ">nargs</code>&nbsp;member of&nbsp;<code style="font-style: inherit; "><a href="en/JSFunctionSpec">JSFunctionSpec</a></code>tells the engine to provide at least that many args, so you can generally hardwire the local root indices (argv{{ mediawiki.external(3) }} rather than argv{{ mediawiki.external('argc') }}). If more arguments are passed and you don't care (you aren't writing a varargs-style function), you can just overwrite the extra arguments with the locally rooted jsvals.</p>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><code style="font-style: inherit; "><a href="en/JSFastNative">JSFastNative</a></code>s cannot ask for extra local roots, and the<code style="font-style: inherit; ">nargs</code>&nbsp;guarantee does not apply to them.</p>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Root as you go</b>&nbsp;to avoid newborn pigeon-hole problems:</p>
    <pre class="eval" style="margin-top: 0px; margin-bottom: 1.286em; padding: 0px; white-space: normal; ">
JSString *str1, *str2;&nbsp;<b>/* Bad! */</b>&nbsp;str1 = JS_ValueToString(cx, argv[0]); if (!str1) return JS_FALSE; str2 = JS_ValueToString(cx, argv[1]); if (!str2) return JS_FALSE; SomethingThatMightCallTheGC();&nbsp;<b>/* Good! */</b>&nbsp;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();</pre>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Beware {{ Bug(438633) }}.</b>&nbsp;Code that uses<code style="font-style: inherit; "><a href="en/JS_CompileScript">JS_CompileScript</a></code>,&nbsp;<code style="font-style: inherit; "><a href="en/JS_CompileFile">JS_CompileFile</a></code>, or<code style="font-style: inherit; "><a href="en/JS_CompileFileHandle">JS_CompileFileHandle</a></code>&nbsp;must root the new script as described in the JSAPI User Guide under&nbsp;<a href="en/JSAPI_User_Guide#Compiled_scripts">Compiled scripts</a>.</p>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">Avoid malloc'ing temporary storage that contains unrooted jsvals:</p>
    <pre class="eval" style="margin-top: 0px; margin-bottom: 1.286em; padding: 0px; white-space: normal; ">
<b>/* Bad! */</b>&nbsp;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 &lt; 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);&nbsp;<b>/* Good! */</b>&nbsp;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 &lt; len; i++) { str = JS_NewStringCopyZ(cx, GetNativeString(i)); if (!str) return JS_FALSE; val = STRING_TO_JSVAL(str); if (!JS_SetElement(cx, myArrayObj, i, &amp;val)) return JS_FALSE; } OtherStuffThatMightGC();</pre>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">Note that this example also shows tip #3 (root as you go).</p>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Follow the request model in multithreaded applications.</b>&nbsp;See&nbsp;<code style="font-style: inherit; "><a href="en/JS_THREADSAFE">JS_THREADSAFE</a></code>. If you don't follow those rules scrupulously, GC could occur on one thread while another thread is in the JavaScript interpreter or otherwise handling JavaScript pointers. (The GC is not designed to handle that and it will crash.)</p>
  </li>
  <li>
    <p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><b>Don't run the GC at arbitrary times.</b>&nbsp;You can run the GC after some number of scripts, from a&nbsp;<a href="en/JS_SetBranchCallback">branch callback</a>, or from a "GC thread" that wakes up periodically, for example. Beware realtime effects! Just how sensitive are you to latency?</p>
  </li>
</ol>
<h3 id="How_to_Dump_the_GC_Heap" name="How_to_Dump_the_GC_Heap" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 1.142em; font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', Lucida, Arial, Helvetica, sans-serif; ">How to Dump the GC Heap</h3>
<p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">Using these steps you can find all the GC'able items and what they're linked to.</p>
<div class="note">
  <b>Note:</b>&nbsp;In SpiderMonkey 1.8, these features are being replaced with a new function,&nbsp;<code style="font-style: inherit; "><a href="en/JS_DumpHeap">JS_DumpHeap</a></code>.</div>
<h4 id="Steps" name="Steps" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', Lucida, Arial, Helvetica, sans-serif; ">Steps</h4>
<ul style="margin: 0px 0px 1.286em; padding: 0px; list-style-type: none; ">
  <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Define GC_MARK_DEBUG in the project that builds the SpiderMonkey Files</li>
  <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Add code similar to the following around your call to JS_GC</li>
</ul>
<pre style="margin-top: 0px; margin-bottom: 1.286em; padding: 0px; white-space: normal; font-size: 14px; line-height: 18px; ">
extern "C" FILE* js_DumpGCHeap; js_DumpGCHeap = fopen("c:\\jsds-roots.txt", "w"); JS_GC((*i)-&gt;jsc); fclose(js_DumpGCHeap); js_DumpGCHeap = NULL;</pre>
<h4 id="Interpreting_the_results" name="Interpreting_the_results" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', Lucida, Arial, Helvetica, sans-serif; ">Interpreting the results</h4>
<p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">Results will come out like the following:</p>
<pre style="margin-top: 0px; margin-bottom: 1.286em; padding: 0px; white-space: normal; font-size: 14px; line-height: 18px; ">
061f6810 object 06202ED8 Root via global object(Root @ 0x061f6810).</pre>
<p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; ">This points that the JSObject (0x061f6810) with private data (0x06202ED8) and class name "Root" is referenced by the global object (cx-&gt;globalObject).</p>
<h4 id="Hints" name="Hints" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', Lucida, Arial, Helvetica, sans-serif; ">Hints</h4>
<ul style="margin: 0px 0px 1.286em; padding: 0px; list-style-type: none; ">
  <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">In order to filter results you must edit the function gc_dump_thing in jsgc.c. As an example, adding the following to the top of the method will filter out strings:</li>
</ul>
<pre style="margin-top: 0px; margin-bottom: 1.286em; padding: 0px; white-space: normal; font-size: 14px; line-height: 18px; ">
if(flags &amp; GCX_STRING) return;</pre>
<p style="margin: 0px 0px 1.286em; padding: 0px; line-height: 1.5em; "><br />
  &nbsp;</p>
<div class="originaldocinfo" style="font-size: 11px; ">
  <h2 id="Original_Document_Information" name="Original_Document_Information" style="margin: 0px 0px 0.8em; padding: 0px; font-size: 13px; ">Original Document Information</h2>
  <ul style="margin: 0px 0px 1.286em; padding: 0px; list-style-type: none; ">
    <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Author:&nbsp;<a class="link-mailto" href="mailto:rginda@netscape.com">Robert Ginda</a></li>
    <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Contributor:&nbsp;<a class="link-mailto" href="mailto:thehesiod@gmail.com">Alex Mohr</a></li>
    <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Last Updated Date: January 3, 2005</li>
    <li style="padding: 0px; background-image: none; background-position: initial initial; background-repeat: initial initial; ">Copyright Information: Copyright (C)&nbsp;<a class="link-mailto" href="mailto:rginda@netscape.com">Robert Ginda</a></li>
  </ul>
</div>
<p>&nbsp;</p>
このリビジョンへ戻す