Skip to content

Commit fedec73

Browse files
authored
Fix memory leak by disposing entire tree if top node is being disposed. (helix-toolkit#1928)
* Fix WINUI package crash after diposing Viewport3DX. * Dispose entire tree if top node is being disposed. * Dispose all children while disposing viewport. * Dispose all items in ModelContainer3DX.
1 parent 8b7465c commit fedec73

File tree

9 files changed

+111
-9
lines changed

9 files changed

+111
-9
lines changed

Source/HelixToolkit.SharpDX.Shared/Model/Scene/Abstract/GroupNodeBase.cs

+4
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ protected override bool OnHitTest(HitTestContext context, Matrix totalModelMatri
294294
protected override void OnDispose(bool disposeManagedResources)
295295
{
296296
Cleared = null;
297+
foreach (var c in this.ItemsInternal)
298+
{
299+
c?.Dispose();
300+
}
297301
base.OnDispose(disposeManagedResources);
298302
}
299303
}

Source/HelixToolkit.SharpDX.Shared/Viewport/ViewportCore.cs

+4
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ private void ViewCubeClicked(Vector3 lookDirection, Vector3 upDirection)
246246
protected override void OnDispose(bool disposeManagedResources)
247247
{
248248
Detach();
249+
if (disposeManagedResources)
250+
{
251+
Items.Dispose();
252+
}
249253
base.OnDispose(disposeManagedResources);
250254
}
251255
}

Source/HelixToolkit.SharpDX.SharedModel/Controls/ModelContainer3DX.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#endif
1414

1515
#if NETFX_CORE
16-
using Windows.UI.Xaml;
16+
using Windows.UI.Xaml;
1717
using HelixToolkit.UWP.Utilities;
1818
namespace HelixToolkit.UWP
1919
#elif WINUI
@@ -672,7 +672,7 @@ public void Detach(IRenderHost host)
672672
if (Interlocked.Decrement(ref d3dCounter) == 0)
673673
{
674674
foreach (var renderable in Renderables)
675-
{
675+
{
676676
renderable.Detach();
677677
renderable.Invalidated -= RenderableInvalidated;
678678
}
@@ -756,6 +756,13 @@ protected virtual void Dispose(bool disposing)
756756
{
757757
attachedRenderHosts.Clear();
758758
Detach();
759+
foreach (var item in Items)
760+
{
761+
if (item is IDisposable d)
762+
{
763+
d.Dispose();
764+
}
765+
}
759766
// TODO: dispose managed state (managed objects).
760767
viewports.Clear();
761768
currentRenderHost = null;

Source/HelixToolkit.UWP.Shared/Controls/Viewport3DX.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,13 @@ protected virtual void Dispose(bool disposing)
931931
if (disposing)
932932
{
933933
EffectsManager = null;
934-
Camera = null;
934+
Camera = null;
935+
foreach (var item in Items)
936+
{
937+
item.Dispose();
938+
}
939+
viewCube?.Dispose();
940+
coordinateSystem?.Dispose();
935941
Items.Clear();
936942
if (hostPresenter.Content is IDisposable host)
937943
{

Source/HelixToolkit.UWP.Shared/Model/Element3D/Abstract/GroupElement3D.cs

+27-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public abstract class GroupElement3D : Element3D
3737
public static readonly DependencyProperty ItemsSourceProperty =
3838
DependencyProperty.Register("ItemsSource", typeof(IList<Element3D>), typeof(GroupElement3D),
3939
new PropertyMetadata(null,
40-
(d, e) => {
40+
(d, e) =>
41+
{
4142
(d as GroupElement3D).OnItemsSourceChanged(e.NewValue as IList<Element3D>);
4243
}));
4344

@@ -147,7 +148,7 @@ protected override void OnApplyTemplate()
147148
Items.Add(item);
148149
}
149150
}
150-
if(OctreeManager is Element3D elem)
151+
if (OctreeManager is Element3D elem)
151152
{
152153
Items.Add(elem);
153154
}
@@ -233,7 +234,7 @@ private void OnItemsSourceChanged(IList<Element3D> itemsSource)
233234
Children.Remove(child);
234235
}
235236
}
236-
if(itemsSourceInternal == null && itemsSource != null && Children.Count > 0)
237+
if (itemsSourceInternal == null && itemsSource != null && Children.Count > 0)
237238
{
238239
throw new InvalidOperationException("Children must be empty before using ItemsSource");
239240
}
@@ -287,5 +288,28 @@ private void S_CollectionChanged(object sender, NotifyCollectionChangedEventArgs
287288
break;
288289
}
289290
}
291+
292+
protected override void Dispose(bool disposing)
293+
{
294+
if (disposing)
295+
{
296+
if (itemsSourceInternal is INotifyCollectionChanged s)
297+
{
298+
s.CollectionChanged -= S_CollectionChanged;
299+
}
300+
if (itemsSourceInternal != null)
301+
{
302+
foreach (var item in itemsSourceInternal)
303+
{
304+
item.Dispose();
305+
}
306+
}
307+
foreach (var child in Children)
308+
{
309+
child.Dispose();
310+
}
311+
}
312+
base.Dispose(disposing);
313+
}
290314
}
291315
}

Source/HelixToolkit.UWP.Shared/Model/Element3D/ItemsModel3D.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,18 @@ public virtual void Clear()
392392

393393
protected override void Dispose(bool disposing)
394394
{
395-
Clear();
395+
if (disposing)
396+
{
397+
if (itemsSource is INotifyCollectionChanged n)
398+
{
399+
n.CollectionChanged -= ItemsModel3D_CollectionChanged;
400+
}
401+
foreach (var item in elementDict)
402+
{
403+
item.Value?.Dispose();
404+
}
405+
Clear();
406+
}
396407
base.Dispose(disposing);
397408
}
398409
}

Source/HelixToolkit.Wpf.SharpDX.Shared/Controls/Viewport3DX.cs

+6
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,12 @@ protected virtual void Dispose(bool disposing)
19261926
}
19271927
Camera = null;
19281928
EffectsManager = null;
1929+
foreach (var item in Items)
1930+
{
1931+
item.Dispose();
1932+
}
1933+
viewCube?.Dispose();
1934+
coordinateView?.Dispose();
19291935
Items.Clear();
19301936
}
19311937
// TODO: dispose managed state (managed objects).

Source/HelixToolkit.Wpf.SharpDX.Shared/Model/Elements3D/AbstractElements3D/GroupElement3D.cs

+23
Original file line numberDiff line numberDiff line change
@@ -291,5 +291,28 @@ private void S_CollectionChanged(object sender, NotifyCollectionChangedEventArgs
291291
break;
292292
}
293293
}
294+
295+
protected override void Dispose(bool disposing)
296+
{
297+
if (disposing)
298+
{
299+
if (itemsSourceInternal is INotifyCollectionChanged s)
300+
{
301+
s.CollectionChanged -= S_CollectionChanged;
302+
}
303+
if (itemsSourceInternal != null)
304+
{
305+
foreach (var item in itemsSourceInternal)
306+
{
307+
item.Dispose();
308+
}
309+
}
310+
foreach (var child in Children)
311+
{
312+
child.Dispose();
313+
}
314+
}
315+
base.Dispose(disposing);
316+
}
294317
}
295318
}

Source/HelixToolkit.Wpf.SharpDX.Shared/Model/Elements3D/ItemsModel3D.cs

+19-2
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,28 @@ protected void ItemsModel3D_CollectionChanged(object sender, NotifyCollectionCha
300300
break;
301301
}
302302
}
303-
303+
public virtual void Clear()
304+
{
305+
elementDict.Clear();
306+
var node = SceneNode as GroupNode;
307+
node.Clear();
308+
Children.Clear();
309+
}
304310

305311
protected override void Dispose(bool disposing)
306312
{
307-
elementDict.Clear();
313+
if (disposing)
314+
{
315+
if (ItemsSource is INotifyCollectionChanged n)
316+
{
317+
n.CollectionChanged -= ItemsModel3D_CollectionChanged;
318+
}
319+
foreach (var item in elementDict)
320+
{
321+
item.Value?.Dispose();
322+
}
323+
Clear();
324+
}
308325
base.Dispose(disposing);
309326
}
310327
}

0 commit comments

Comments
 (0)