gpt4 book ai didi

c# - ReactiveUI 绑定(bind)似乎可以防止发生垃圾回收

转载 作者:可可西里 更新时间:2023-11-01 09:14:49 24 4
gpt4 key购买 nike

我们目前正在使用 ReactiveUI 来帮助构建一个相当大的基于 WPF 的 Windows 应用程序。一切都很顺利,直到我们发现我们的应用程序正在消耗大量内存……基本上我们所有的 View 、 View 模型和模型都没有被垃圾收集。

根据 Jet Brains dotMemory 等内存分析器的信息,ReactiveUI 似乎是罪魁祸首。特别是我们在 View 中配置的 ReactiveUI 绑定(bind),即使我们正在使用最佳实践并确保在停用 View 时处理所有绑定(bind)。

以下是我们正在创建的 View 之一的示例。任何关于我们可能哪里出错的想法都将不胜感激。

public partial class RunbookInputsView : IViewFor<RunbookInputsViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
"ViewModel", typeof(RunbookInputsViewModel), typeof(RunbookInputsView));

public RunbookInputsView()
{
InitializeComponent();

this.WhenActivated(d =>
{
d(this.OneWayBind(ViewModel, vm => vm.AddInput, v => v.AddInput.Command));
d(this.OneWayBind(ViewModel, vm => vm.Inputs, v => v.Inputs.ItemsSource));
});
}

object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (RunbookInputsViewModel)value; }
}

public RunbookInputsViewModel ViewModel
{
get { return (RunbookInputsViewModel) GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
}

最佳答案

从问题中很难判断泄漏是从哪里来的。让泄漏发生一段时间,然后使用 windbg(Debugging Tools For Windows 的一部分)附加到进程(注意:您可能需要构建 x86 x64 才能正常工作。)

附加后,通过输入以下命令设置 .net 调试:

.symfix
sxe clr
sxd av
.loadby sos clr

然后您可以使用 !dumpheap -stat 获取每种类型的内存使用情况。这会产生以下格式的输出:(为了便于阅读,我截断了类名和列表。)

0:012> !dumpheap -stat
Statistics:
MT Count TotalSize Class Name
000007fefa55d2e8 1 24 System.[...]TransportSinkProvider
000007fefa55ce08 1 24 System.Run[...]rtSinkProvider
000007fee7c32df0 1 24 System.LocalDataStoreHolder
000007fee7c2ff78 1 24 System.Colle[...]
000007fee7c2ece0 1 24 System.Resources.FastResourceComparer
000007fee7c2ead0 1 24 System.Resources.ManifestBasedResourceGroveler
000007fee7c2ea70 1 24 System.[...]eManagerMediator
000007fee4cc1b70 4 1216 System.Xml.XmlDocument

如果您有内存泄漏,您将在这里看到泄漏的对象。 (应该有很多。)一旦您确定了泄漏的内容,您就可以执行 !dumpheap -type 来获取实际对象的列表。 (对于此示例,我将使用 System.Xml.XmlDocument。类型名称区分大小写,并且必须完全限定。)

0:012> !dumpheap -type System.Xml.XmlDocument
Address MT Size
0000000002af9050 000007fee4cc1b70 304
0000000002afa628 000007fee4cc1b70 304
0000000002b0ea30 000007fee4cc1b70 304
00000000037e2780 000007fee4cc1b70 304

Statistics:
MT Count TotalSize Class Name
000007fee4cc1b70 4 1216 System.Xml.XmlDocument

您的列表可能会大得多,但概率表明泄漏类型的任何随机实例都会是您感兴趣的东西。如果我们对其中一个地址执行 !do ,我们将得到如下所示的输出:

0:012> !do 2af9050
Name: System.Xml.XmlDocument
MethodTable: 000007fee4cc1b70
EEClass: 000007fee4ae7f00
Size: 304(0x130) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll
Fields:
MT Field Offset Type VT Attr Value Name
000007fee4cc2b40 40004fc 8 System.Xml.XmlNode 0 instance 0000000000000000 parentNode
000007fee4cc2258 400050a 10 ...XmlImplementation 0 instance 0000000002af9180 implementation
000007fee4cc22f0 400050b 18 ....Xml.DomNameTable 0 instance 0000000002af92e0 domNameTable
[Entries removed for clarity]
000007fee4cc26f0 400052f 108 ...m.Xml.XmlResolver 0 instance 0000000000000000 resolver
000007fee7c18c48 4000530 126 System.Boolean 1 instance 0 bSetResolver
000007fee7c113e8 4000531 110 System.Object 0 instance 0000000002af9788 objLock
000007fee4cc11b0 4000532 118 ....Xml.XmlAttribute 0 instance 0000000000000000 namespaceXml

您可以对表中列出的任何对象使用 !do 以获取更多信息。 System.StringSystem.Boolean 等类型将吐出它们的实际值。如果从创建它的对象中不清楚,下一步可能是使用 !gcroot -nostacks 来查找对我们对象的引用。

0:012> !gcroot -nostacks 2af9050
HandleTable:
00000000006117d8 (pinned handle)
-> 0000000012a55748 System.Object[]
-> 0000000002af9050 System.Xml.XmlDocument

Found 1 unique roots (run '!GCRoot -all' to see all roots).

还有很多命令,这已经太长了。 !help 命令提供了一个很好的 list 。 (要使用它们中的任何一个,您需要在命令前加上 ! 前缀。!help [command] 提供有关特定命令的详细信息。例如 !help dumpobj:

0:012> !help dumpobj
-------------------------------------------------------------------------------
!DumpObj [-nofields] <object address>

This command allows you to examine the fields of an object, as well as learn
important properties of the object such as the EEClass, the MethodTable, and
the size.

You might find an object pointer by running !DumpStackObjects and choosing
from the resultant list. Here is a simple object:

0:000> !DumpObj a79d40
Name: Customer
MethodTable: 009038ec
EEClass: 03ee1b84
Size: 20(0x14) bytes
(C:\pub\unittest.exe)
Fields:
MT Field Offset Type VT Attr Value Name
009038ec 4000008 4 Customer 0 instance 00a79ce4 name
009038ec 4000009 8 Bank 0 instance 00a79d2c bank

Note that fields of type Customer and Bank are themselves objects, and you can
run !DumpObj on them too. You could look at the field directly in memory using
the offset given. "dd a79d40+8 l1" would allow you to look at the bank field
directly. Be careful about using this to set memory breakpoints, since objects
can move around in the garbage collected heap.

What else can you do with an object? You might run !GCRoot, to determine what
roots are keeping it alive. Or you can find all objects of that type with
"!DumpHeap -type Customer".

The column VT contains the value 1 if the field is a valuetype structure, and
0 if the field contains a pointer to another object. For valuetypes, you can
take the MethodTable pointer in the MT column, and the Value and pass them to
the command !DumpVC.

The abbreviation !do can be used for brevity.

The arguments in detail:
-nofields: do not print fields of the object, useful for objects like
String

关于c# - ReactiveUI 绑定(bind)似乎可以防止发生垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32126163/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com