Closed Bug 1336862 Opened 9 years ago Closed 9 years ago

Iterating over a JS object for its values allocates temporary garbage?

Categories

(Core :: JavaScript Engine, defect)

53 Branch
defect
Not set
normal

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: jujjyl, Unassigned)

Details

Attachments

(1 file)

With Emscripten and asm.js/wasm, we are actively optimizing to generate as little garbage as is necessary to avoid generating GC stuttering that can impact smoothness of WebGL animations. Here is something odd I'm seeing which I don't quite understand: In our OpenAL audio backend implementation, we have a map of "integer ID" -> "audio source" objects for audio items that are currently playing, see https://github.com/kripken/emscripten/blob/master/src/library_openal.js#L261 When a new audio source is created, it is added to the src dictionary, at https://github.com/kripken/emscripten/blob/master/src/library_openal.js#L374 When an audio source is finished, it is 'delete'd from the dictionary, at https://github.com/kripken/emscripten/blob/master/src/library_openal.js#L360 At each animation frame, we need to update each audio source for its parameters, which is done here: https://github.com/kripken/emscripten/blob/master/src/library_openal.js#L40 The surprising thing is that this last line 40 generates temporary garbage each frame as indicated by the DevTools Performance profiler with its excellent "Record Allocations" tool (this tool is disabled by default, enable it by ticking the checkbox at the gear icon on the right in DevTools Performance panel). If I change the 'context.src' dictionary to a flat array, that avoids generating any temporary garbage and we get to run fully garbage clean. (this line is the last of the remaining "running" garbage allocations at each rendered frame in the tested codebase) Is it expected that iterating a "for x in {...}" should generate temporary GC-able objects, and "for(var i = 0; i < [...]; ++i)" does not?
Here is an illustration of what the Allocations tool shows on the given line.
(In reply to Jukka Jylänki from comment #0) > Is it expected that iterating a "for x in {...}" should generate temporary > GC-able objects, and "for(var i = 0; i < [...]; ++i)" does not? Yes we allocate an iterator object (PropertyIteratorObject, a JSObject) that holds a pointer to a malloc NativeIterator.
Thanks - is there a decent way to iterate such an object without generating temporary garbage? Or should I ideally use arrays for these types of scenarios?
I don't think there's a decent way that does not generate temporary garbage. The ES2015 iterator protocol (for-of loops) may create even more garbage because it returns a {done, value} object each iteration :( We sometimes optimize this away in the JIT but I wouldn't rely on that. Using an object as hashmap and using delete is also relatively slow/inefficient. You could use Map but iterating that will also create garbage, so arrays are probably the best option...
Right'o, I think can do away with maps and use arrays and implement a linked list of actively playing sound sources for per-frame iteration. It's a bit clumsy, but should be doable. Thanks!
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: