Conversation
d1cb6ac to
78ea49b
Compare
|
As a rough example of the memory impact of this optimization, loading TypeScript 2.5 typescriptServices.js into the global object on x64 takes:
So the memory savings are around 3% in this case - not huge, but still significant considering there is next to no functional downside (but of course some complexity downsides). For a targeted memory test exercising function instance creation maximally (tests/memory/test-function-expression-1.js):
which comes to around 33%, representing the maximum possible benefit from this change alone. |
|
For the Promise polyfill, which is not very compact memory-wise:
So this change improves the Promise polyfill memory behavior quite a bit, which is quite natural because Promises (even behind the user-provided callbacks) are function-heavy. |
|
So besides reducing GC pressure, this also reduces memory pressure. Nice. 😁 |
|
It would be really nice to have some structured, extensible way of virtualizing properties like this, so that the approach could be applied to a few other properties too. But it seems hard to generalize: the knowledge that the property needs to be virtualized cannot come from the prototype (it would be user visible), and in some cases one doesn't want to actually instantiate the property but still behave as if it existed (e.g. enumeration). |
78ea49b to
909b3ab
Compare
(At this point just some quick testing, not sure if this approach will be merged.)
All constructable functions have a
.prototypeproperty. It points, by default, to an object whose.constructorproperty points back to the function, creating a reference loop. This reference loop prevents most function objects, especially inline callbacks, from being refcount freed. There are several approaches to allow refcount collection of such function objects.One of them is to postpone creation of the
.prototypeproperty until it is actually observed somehow and we must commit to the property's existence. Relevant situations include:.prototypeis writable but not configurable, the new value can be written without creating the object prior to the (over)write.prototype in MyConstructormust return true; does not require creation of the object..prototypeis non-configurable so delete must fail; does not require creation of the object.This approach allows refcount collection of a few basic cases, in particular anonymous functions which are not captured by an outer scope, e.g.:
Unfortunately if the function is given a name, this currently creates another kind of reference loop (scope object containing the function name binding points to the function, and the function points to the scope) so this doesn't get refcount collected:
This case could be allowed to work by reworking the function name binding scope handling. But other cases will still remain.
Tasks:
Future work: