-
Notifications
You must be signed in to change notification settings - Fork 668
Reduce memory leak in tests #10672
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
Reduce memory leak in tests #10672
Conversation
…the biggest impact.
# Conflicts: # src/DocumentationBrowserViewExtension/DocumentationBrowserViewExtension.cs
| private bool isPSSCalledOnViewModelNoCancel = false; | ||
| private readonly DispatcherTimer _workspaceResizeTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 500), IsEnabled = false }; | ||
|
|
||
| private ReadyParams sharedExtensionParams; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding a shared viewLoadedParams object for all viewExtensions so we can call dispose on it later.
guard notification extension from double dispose issue add watchview cleanup to watch3dview unload instead of calling it from DynamoWindow close
…r test suite. Still not sure it's actually appropriate...
change name of shared params
mmisol
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments. Looks good for the most part but the TODOs worry me a little
| { | ||
| //TODO we should be careful with this, viewExtensions also have their shutdown method called | ||
| //when the dynamoWindow closes so it's possible there are some double dispose issues for ours or | ||
| //external extensions. Looking for feedback here! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the extensions I have seen we usually call Dispose from Shutdown. I'm not sure there is any documentation established around that pattern though.
You might want to check in which cases, DynamoView.Dispose was being called directly, and maybe use another DisposeAllButExtensions in the context of WindowClosed. In any case this is not so bad as any error will be catched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DynamoView.Dispose was never called!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could integrators be using it? If not, maybe we can remove the part where we Dispose extensions, just to keep things the way they were before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is a possible solution, the safest thing to do for now is to leave out the ViewExtension dispose calls and properly document the relationship between shutdown and dispose. - BUT that may leave user viewExtensions hanging around with being disposed - unlikely to cause issues except in tests I suppose.
|
|
||
| Open(@"UI\CoreUINodes.dyn"); | ||
|
|
||
| //TODO why did this pass before? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anything pending to investigate here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, this seems fine, must have temporarily broken something as I was in progress.
|
https://master-15.jenkins.autodesk.com/view/DYN/job/DYN-DevCI_Self_Service_net47/1/consoleText - only failing tests are the analytics ones that Tibi has fixed in his latest prs. @aparajit-pratap @mmisol what do you think we should do for the otherwise this should be complete - believe I addressed all comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjkkirschner still not quite sure why you're explicitly calling DynamoView's Dispose method. Also, I think we can Dispose view extensions directly in the WindowClosed method for DynamoView itself, no?
Lastly, I had a question about FilteredResult in SearchViewModel and making that an ObservableCollection in the future.
| { | ||
|
|
||
| Dispose(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Dispose is called after Shutdown in DynamoView.WindowClosed, what's the need call it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aparajit-pratap - this depends on if we leave the ViewExtension disposal calls in or not - @mmisol was suggesting maybe leaving them out to keep the behavior as it was before this PR - if we do that, I can leave this.
If we keep the disposal calls after shutdown, I can remove this.
mmisol
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjkkirschner I would say to leave this as it was with regards to disposing extensions is the ideal but it's not something absolutely needed as we are still catching any errors that may occur from double disposals. Also, like we mentioned, it's more like a documentation issue that we could take separately.
aparajit-pratap
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking a look further I see that the ViewExtensionManager holds a reference to a collection of all ViewExtension objects and its Dispose method merely clears that collection rather than disposing each view extension. See
| public void Dispose() |
I think it should own the disposal of each view extension and then DynamoView can simply call
Dispose on its viewExtensionManager property/field.
|
@aparajit-pratap I'll take a look at moving the disposal into the ViewExtensionsManager if you prefer that approach? |
|
@aparajit-pratap fixed, and also, this was a good catch it freed up even more memory in my test suite! |
Purpose
Before these changes running just DynamoCoreWPFTests.dll consumed 6GB of ram on my machine.
After these changes memory use is approximately 1GB and forcing a garbage collection brings it down to 300~ megs.
There are likely a bunch of extraneous changes here and also - these changes are just WIP - they need to be cleaned up.
But here are some notes on what I found:
many retention paths were holding onto the underlying canvases in Helix.
WorkspaceView and DynamoView left a bunch of handlers dangling.
Static references under some circumstances do not get GC'd as they live in a global object the CLR builds, these might not get cleaned up during tests so I've set them null during cleanup. Need to check if these are required.
I noticed some very strange behavior with readonly fields not being cleaned up - research seems split on if these can be a problem, need to check if this can be reverted.
Because of the design of
ViewLoadedParamspassed to ViewExtensions it's difficult to cleanup the handlers that are created there, I ended up storing a reference to a single params and using it for all view extensions that are loaded at Dynamo startup - I think this is okay. - though likely we could solve this more elegantly - it also means that view extensions loaded after startup, still leak, but thats an edge case.InforBubble (error view) leaks - made some improvments.
removed Suppress GC on Defaultwatch3dViewModel - need to check if this was required - I don't see why we would want this though - we don't implement a finalizer.
removed a bunch of anonymous event handlers which caused leaks, while these are great and make code more succinct and readable, I think we should disallow their use unless the author memory profiles them or has a convincing argument why they will not introduce a leak... usually they are fine if they do not reference any external objects, IE an event on the same object on which the handler is defined.
CustomNodeWorkspaceModelsleak - these were never cleaned up because we only clean the workspaces in the DynamoModel.Workspaces collection - but custom node workspaces are not in that collection unless they are actually open in a tab. When the customNodeManager is cleaned up now, these are uninitialized by the CNM which cleans them up.Declarations
Check these if you believe they are true
*.resxfiles