-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC Remove event pooling #1612
RFC Remove event pooling #1612
Conversation
cc @jordwalke ? |
I would counter-argue and say anything we can do to reduce GC is a win. While I agree that this isn't the worst place for allocations, I don't see any really compelling reason to take a step backwards. There's a tradeoff, but I wouldn't call it a "great cost", I can count on 1 hand the number of times it's come up in the past year. Logging events is annoying but as you found out easily solved so I think we should leave this as is (and document better). |
I understand your point, but from my perspective I've seen a handful of people get confused by it on IRC (which indicates that it's at least unintuitive behavior):
My intuition (which may be completely off) is that the overhead of dealing with pooled events is greater than the cost incurred on the GC (which would probably occur during an idle frame anyway). Even if that isn't that case, I just can't imagine pooling events to actually have a measurable impact in non-synthetic tests. If your information suggests otherwise then by all means, shoot me down, but it feels like premature optimization to me. |
IIRC we added or fixed event pooling after seeing a lot of GC thrash for mouse move events which have very high frequency (we originally didn't support these). Even when nothing is acting on these. Pooled descriptors is indeed something we want to introduce to avoid thrash in extreme cases where updates happen on every mouse or They're generally easy to predict when they can be reused because you're not expected to hold on to anything created in the render function of a component. Expect possibly for animation which would need to tie into the pooling system. DOM events are also reused in a similar way. I'm not saying it's right. Ideally we should encourage more immutable behavior but there is existing precedence for this behavior. Mutating React objects is already considered bad practice but we could do a Object.preventExtension call to explicitly ensure that nobody adds additional properties to the object.
|
Yes, pooling was in response to an actual issue. And yes, it's not the worst offender. But we should also be fixing the other offenders. For example, did you know we're cloning every props object every time a component reconciles! |
@sebmarkbage For mouse move, couldn't we simply make the instantiation of the event object lazy? That would take care of the case where no one is listening. As for descriptors, isn't that contradictory to the recent commits? I may have misinterpreted, but I remember hearing that being able to reuse descriptors since that commit to be a feature (or at least, that some people chose to interpret it that way). @jordwalke That's where it doesn't really add up in my head, if we have significantly worse offenders, have we been able to observe improvements from pooling just events? I'm at loss as to how 1-3 transient objects per frame can cause thrashing by itself (the browser doesn't pool event objects itself). Are you sure there weren't external factors at fault? Like say, indefinitely appending to a string/array for every mouse move, which could mess up memory allocation. (PS. I think this is one of those things that more makes sense when/if more features in React adopt it) |
@syranide Descriptors can be reused in the same owner subtree which created it. E.g. render() {
var a = <div />;
return <div>{a}{a}</div>;
} If this render method is reexecuted, we can reuse the same object because all subtrees would rerender with the new object and they shouldn't hold a reference to the old one. (Every other render so that the old value can be used in shouldComponentUpdate.) We lazily attach listeners. Lazily attaching listeners doesn't really help much since these events are often used to determine whether you should do something rather than not listening at all. It does seem odd that it would have a significant effect. Perhaps it was only in benchmarks. Someone actually hit this issue yesterday and asked about it. Another hazard is that people defensively clone in each component, leading to more memory thrash than if they could all share the same copy. It might be worth revisiting. As you said, it makes more sense if more React features adopt pooling as a strategy. |
btw @jordwalke: cloning objects is necessary because of this existing pattern: https://github.com/facebook/react/blob/master/src/browser/ui/__tests__/ReactDOMComponent-test.js#L72 |
It seems to me like React will go the way of more pooling. Closing this. |
I couldn't really find anyone on IRC who really knew why we do this. It's annoying to debug and people often don't understand what's happening.
I understand the idea of decreasing the pressure on the GC, but I fail to see how pooling events is going to matter, we're talking worst-case of a consistent stream of about 2 events per frame (give or take, or?). If all we do is dispatch events and there is no render, any pressure on the GC should be imperceptible and any half-decent GC shouldn't find it hard to deal short-lived objects. If any of those update an immutable store we're going to see a handful of objects created and unreferenced, if any of those cause a React render, we might be seeing hundreds of objects created and unreferenced.
For internal classes, pooling is great no matter what really, but we're talking about a public API that's also rather common and standardized. This is not intuitive behavior and so event pooling comes at a great cost, but from where I'm standing there doesn't seem to be an equal or greater benefit.
PS. Only after doing this PR did I discover that there actually is a
event.persist()
method, if we stick to pooled events, we really should document it as it definitely makes it less of a pain.PS2. PR because I can, not because I care :)