-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Potential resource leak in unsubscribe loop #1256
Comments
@briancavalier yes there is. unsubscribe should be called safely. |
Thanks for pointing that out @briancavalier! Nice of the author of Most.js to lend a hand. 💖 |
@Blesh @briancavalier upon further review, this may not be so clear cut, and I have a feeling this is related to #1186. When an error is thrown from the private
If we take the second approach, we'll also have to wrap the unsubscribe(): void {
if (this.isUnsubscribed) {
return;
}
this.isUnsubscribed = true;
let errors: Array<any>;
let errorHappened = false;
const { _unsubscribe, _subscriptions } = (<any> this);
(<any> this)._subscriptions = null;
if (isFunction(_unsubscribe)) {
try {
_unsubscribe.call(this);
} catch (e) {
errorHappened = true;
(errors || (errors = [])).push(e)
}
}
if (isArray(_subscriptions)) {
let index = -1;
const len = _subscriptions.length;
while (++index < len) {
const subscription = _subscriptions[index];
if (isObject(subscription)) {
try {
subscription.unsubscribe();
} catch (e) {
errorHappened = true;
(errors || (errors = [])).push(e)
}
}
}
}
if (errorHappened) {
if (errors.length > 1) {
throw errors;
} else {
throw errors[0];
}
}
} As you can see, it's a little funny. What do we do if we encounter many errors disposing our child subscriptions? re-throw them individually? as a group? I know this is goes against my opinion in #1186, but perhaps the best thing to do is nothing, and provide guidance that users shouldn't throw errors from their |
@trxcllnt throw them as a group, I'd say. I have a PR ready to do that covers at least some of the leak. I need to add more tests to be sure, though. |
I don't think it would be responsible for us to just say "don't throw in your unsubscribes" and not handle the unsubscriptions as we have in this PR. |
@Blesh I think it's perfectly responsible as we laid it out in our design document which we thought over for months. cc @headinthebox |
Seems like a possible source for memory leaks that we just fixed at no cost to performance or ergonomics. I'd hate to remove the fix without a good reason. |
It's the same rule as in any language, you don't throw in finalizers, simple as that |
I'm unfamiliar with this rule or how it applies to this method call. Perhaps I'm just confused: Are you asking us to remove the memory leak protection code? Because currently, it will:
and if we remove it:
... It seems pretty clear we should keep the code in there. We're protecting ourselves from user-land errors, since the unsubscribe function could be provided by users of the type. |
FWIW: If we do decide to remove this protection code, then we should also remove the code that is trying to Because this is very, very similar to what we're doing and talking about in #1186... and there's still some hard work to go there (Involving errors thrown in the same call stack in a next handler during subscription phase and before the unsubscribe logic is even returned). |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Subscription builds up an array of subscriptions in
add()
, which is later torn down in a loop when unsubscribe() is called. It seems that if a particularsubscription.unsubscribe
call throws, the subscriptions later in the array will never be unsubscribed. If those subscriptions represent resources, perhaps from Observable.create calls as mentioned in Guidelines bullet 4, it appears that the resources would be leaked.Is there a potential leak there?
The text was updated successfully, but these errors were encountered: