-
-
Notifications
You must be signed in to change notification settings - Fork 116
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
fix(core): unsubscribe every possible events #611
Conversation
ghiscoding
commented
Oct 22, 2020
•
edited
edited
- causes memory heap size to keep growing
- ref Angular-Slickgrid is causing a memory leak in my application #610
- causes memory heap size to keep growing
@tannenbaums There is only 1 more subscription that I'm not sure how to unsubscribe since it's in the App Module (appInitializerFactory) on this line. I'm not sure if it's even possible but that is a possible left open one. So give that another try and see if latest commits help. Thanks |
Codecov Report
@@ Coverage Diff @@
## master #611 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 149 149
Lines 9974 9980 +6
Branches 3528 3381 -147
==========================================
+ Hits 9974 9980 +6
Continue to review full report at Codecov.
|
Sounds great, I’ll check it out a bit later, I have to juggle my work load with this. I made my own changes, but didn’t get a chance to test yet. But I’ll try your first when I get freed up…
|
Definitely making progress, the BasicGridComponent is not leaking anymore but the others still do. I’ll continue to try fixing on my end and look into that line in app module.
|
I’d like to mention another point: if you assign the subscription to a variable like this:
this.changeSubscriber = componentOuput.componentRef.instance.onItemChanged.subscribe((item) => {
and then unsubscribe on destroy, there can still be a problem. Because if the method that subscribes get called more than once, what happens is, your variable only has a ref to the last subscription, but the other ones from previous calls are still floating around. So I think that it’s safer to always add them to a collection like yours subscriptions collection. Because then when we loop over the collection and unsubscribe it’ll get every single one of them.
In the version that I started modifying (but didn’t have a chance to finish yet, because had to deal with users) I added another field to the SharedService called OpenedSubscriptions and added the service to every component that needed this treatment, and then pushed every subscription that was floating onto it. And then in angular-slickgrid component.destroy I just added this line
this.sharedService.globalSubscriptions = unsubscribeAllObservables(this.sharedService.openSubscriptions);
right below this:
// also unsubscribe all RxJS subscriptions
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
What do you think?
|
Sure I can change them to loop through subscriptions array, I'll do that tomorrow but I doubt that would make much difference in this case though. |
@tannenbaums |
Looks like one more example is good now: 10 RowSelection.
The others are still the same problem.
|
Well I can't go further than that, so if you find something else than please share it, else I will merge the PR as it is in the coming days. |
Ok np. I will continue to try things out on my end though.
Thank you for all your help!!
|
Sure I would of course rather fix any memory leaks as much as possible. When you said only Example 10 got fixed, are the other grids without auto-resize still leaking (Examples 1, 6, 10, 15, 20)? I think you have only confirmed Examples 1 and 10 so far, not sure about the others. I also only rewrote the Example 4 to use an |
Sorry I wasn’t clear, I was confirm that 1 and 10 got fixed and all the others you mentioned: 6, 15, 20 are still leaking.
Yes I think so too, Angular called destroy for you.
|
@tannenbaums
The fact that that both were bound to document/body were most probably a big memory leak, especially number 2 I would assume since it's used in most grids. You can give another try, that should help a bit more |
I ran a test on your latest changes, and I tested 1 to 20.
The results:
Pass:
1,4,8,10,14,16,18
Fail:
2,3,5,6,7,9,11,12,13,15,17,19,20
|
Well I am done on my side, there's nothing else for me to search for, I have fixed everything I could find. What you could do to help though is go on these Examples and disable all the grid option flags to disable most extensions/plugins and see if it stops leaking then re-enable some of these flags to find what extension/plugin might be leaking. You can start by disabling |
- the 2nd argument is actually a selector while the method ref should be on 3rd argument but again it's not mandatory with jQuery and will remove everything when not provided which is what we want
Yes exactly!
So I finally found what makes the 2nd example leak. It’s this code:
{
id: 'completed', name: 'Completed', field: 'completed', type: FieldType.number, sortable: true, minWidth: 100,
formatter: customEnableButtonFormatter,
onCellClick: (e, args) => {
this.toggleCompletedProperty(args && args.dataContext);
}
}
If you remove the line in italic, it’ll stop leaking. I think the reason is because this basically causes that the grid now has a ref to a column object which has an onCellClick event that has a ref to a method in the component (in this case the Formatter component), so it won’t release the component. But I’m not sure how to fix it. What do you think?
|
Right now my only way to resolve this is declare the method outside the component, which works, but I hope there’s a better solution…
|
hmm that is that, under the hood the column So as I wrote in first paragraph, technically speaking the <angular-slickgrid gridId="grid22" (onAngularGridCreated)="angularGridReady($event)"
(sgOnClick)="onCellClicked($event.detail.eventData, $event.detail.args)"
[columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions" [dataset]="dataset">
</angular-slickgrid> I'd like to know if it's really that GridEventService causing the issue
BTW, I don't see any italic line in your GitHub reply, maybe because you replied by email, so I'm not fully sure what you mean in this quote, would you mind pasting the code change you did. Also the column |
Ok I’ll try that, thank you!
Regarding the bug: I think (and this is just my two cents) that, this one is not a subscribe/unsubscribe issue, but rather that some code either in Angular-Slickgrid or maybe in SlickGrid itself, is not clearing out the reference to the column definition collection. And thus, in this case, the collection contains an even handler that has a ref to the GridFormatterComponent (because the even handler contains this.toggleCompletedProperty(), and “this” is pointing to the component). And that’s why it’s not being released from memory. That’s why, if I move the toggleCompletedProperty method outside of the component (I declare a const on top of the component) the problem goes away.
|
I’ve never used yarn before. After installing and running yarn run build on the root of the project (which includes the samples) I get all these errors (attached). Any idea?
|
I can't see your attachment, probably because you replied by email, you should use GitHub website to add print screen, you can run I'd like to confirm if you tried with the regular SlickGrid <angular-slickgrid gridId="grid22" (onAngularGridCreated)="angularGridReady($event)"
(sgOnClick)="onCellClicked($event.detail.eventData, $event.detail.args)"
[columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions" [dataset]="dataset">
</angular-slickgrid> |
Yes sorry I was using email.
Yes I did your suggestion of putting it in the html exactly as you suggested below, and then there’s NO leak!!
I tried running npm run build, but it’s just returning gracefully and nothing seems to be happening.
Can I put the errors directly here in the email? It’s a bunch of these:
BUILD ERROR
node_modules/@types/babel__traverse/index.d.ts(212,49): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(212,53): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(212,55): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(212,57): error TS1109: Expression expected.
node_modules/@types/babel__traverse/index.d.ts(212,61): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(212,69): error TS1128: Declaration or statement expected.
node_modules/@types/babel__traverse/index.d.ts(212,83): error TS1011: An element access expression should take an argument.
node_modules/@types/babel__traverse/index.d.ts(213,9): error TS1136: Property assignment expected.
node_modules/@types/babel__traverse/index.d.ts(213,31): error TS1005: ']' expected.
node_modules/@types/babel__traverse/index.d.ts(213,32): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(213,33): error TS1128: Declaration or statement expected.
node_modules/@types/babel__traverse/index.d.ts(213,65): error TS1005: '(' expected.
node_modules/@types/babel__traverse/index.d.ts(214,5): error TS1135: Argument expression expected.
node_modules/@types/babel__traverse/index.d.ts(214,9): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(215,19): error TS1005: '(' expected.
node_modules/@types/babel__traverse/index.d.ts(216,12): error TS1005: ')' expected.
node_modules/@types/babel__traverse/index.d.ts(347,48): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(347,52): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(347,54): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(347,61): error TS1005: ')' expected.
node_modules/@types/babel__traverse/index.d.ts(347,68): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(347,69): error TS1128: Declaration or statement expected.
node_modules/@types/babel__traverse/index.d.ts(347,87): error TS1005: '(' expected.
node_modules/@types/babel__traverse/index.d.ts(356,40): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(356,46): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(359,31): error TS1005: '?' expected.
node_modules/@types/babel__traverse/index.d.ts(359,44): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(359,61): error TS1005: '(' expected.
node_modules/@types/babel__traverse/index.d.ts(359,62): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(359,76): error TS1005: '(' expected.
node_modules/@types/babel__traverse/index.d.ts(359,77): error TS1005: ')' expected.
node_modules/@types/babel__traverse/index.d.ts(366,60): error TS1005: '?' expected.
node_modules/@types/babel__traverse/index.d.ts(366,66): error TS1005: ':' expected.
node_modules/@types/babel__traverse/index.d.ts(366,73): error TS1005: ',' expected.
node_modules/@types/babel__traverse/index.d.ts(366,81): error TS1005: ';' expected.
node_modules/@types/babel__traverse/index.d.ts(366,99): error TS1005: '(' expected.
|
ahh yeah I remember that problem, I had it too, I think it's because I need a newer version of TypeScript in the project because, for some unknown reasons it updated to latest version of long story short, it's probably easier if I release a version tomorrow |
I’m glad you came to that conclusion…☺
Thank you,
|
I found out that if we overwrite the |
I pushed a new patch version |
Thank you for that! I’m not sure, I updated to the latest but still not seeing results. Let me ask you this:
I see that there’s 2.22.5 and ^2.22.5 do I need to make sure I get the one with ^? Or do they both have the mem-leak fixes?
|
I pushed the changes under latest version |
Oh I see, ok.
Well sadly to say, I have an empty component, even if I add just add this: (with nothing in the ts file)
<angular-slickgrid
</angular-slickgrid>
I have a leak, and if I remove: no leak. This is crazy.
Do you think it might have to do with the fact that I’m using the latest version of angular, while angular-slickgrid is using 7?
|
I don't think that the version of Angular I use has anything to do with that, to create the lib package I use ng-packagr, that produces FESM2015 and UMD formats. If there's anything, it could be I'm not sure that I want to go over Angular 8 in the lib project yet, I know they changed to Ivy in Angular 9 so I wanted to stick with Angular 8 for some time. The PR #617 for Angular 8 is not merged yet, I'll do a future release as a |
I hear you. In the meantime I decided to start digging in the heap and see if I can trace where does Angular-Slickgrid hold a ref to my component, which in this specific case it’s called: CaseListingComponent
Check out below, looks like ViewRef inside AngularSlickgridComponent is holding a ref to CaseListing…
|
Every time you post a print screen of attachment via an email reply I can't see it in GitHub, so I don't know what you posted. If you have a way to fix whatever you posted, please make a PR, there isn't much more I can do on my side. Thanks |
Ok I now see the image but it's too small, I can't see the text lol... but still I don't know what else to do. What are the grid options that you're using with that grid? I assume you use some of the features. |
That is a great reference but I still don't have a clue on how to fix that, I don't know Angular in depth enough (I understand the ViewRef concept but I don't understand what is good and what is wrong) so I don't know what to know (in fact I haven't used Angular in couple months, we are using something else for current project). If you have a way to fix it, please please make a PR. |
Well in AngularUtilService you are assigning a viewRef I thought it has todo with that...no? |
you have a line like this: this.appRef.attachView(componentRef.hostView); this looks like it has a lot to do with this issue...but i might be wrong... |
So you're using the Row Detail then, if you see in the AngularUtilService, there's a link which point to what I found to dynamically load an Angular Component into the Row Detail. The link is Angular Pro Tip: How to dynamically create components in . I did not analyze the code much, I just reuse what was in the article to get the Row Detail working (AngularUtilService is mainly used for Row Detail only). |
All I have is an html template which has this: |
Well I don't know why because as I said that ViewRef that you found is really only used by the Row Detail (I search in the lib), so I don't know why it creates that structure. |
I have very good news!!! I didn't test it properly this morning, must have been some sort of a refresh/caching issue. Thank you so much for all your on-going help and support!! |
that is indeed excellent news, thanks for all the communication and feedback 🚀 😄 |
Hi, I just opened up another issue. After you fixed the memory leak last week, although I was able to see that my components now are only loaded once, but to my dismay I was still having problems. So I continued digging and now I believe I finally found the cause: there's still another type of memory leak called DOM Leak. If you can take a look I would greatly appreciate. This time I was able to confirm that once it's fixed on your end, my app should be fine. |