WPF RichTextBox 选项卡选择占用系统内存!

发布于 2024-07-30 17:35:01 字数 415 浏览 1 评论 0原文

我在 WPF / MVVM 中有一个 TabControl,它绑定到 ObservableCollection 之上的 ItemsSource。 每个选项卡都有自己的集合和与图像、Richtextbox 和用户输入框等组件的绑定,并且一切似乎都运行良好。

然而,我注意到每次切换选项卡时,它都会使用大约 100k 的系统内存,而这些内存永远不会被回收! 如果我按住 ctrl-tab 循环浏览所有选项卡,我可以在一分钟内用完 200 兆内存。

现在 - 我创建了一个空白的 WPF 应用程序,仅包含一个选项卡控件,并且它还为每个选项卡开关使用内存(尽管少得多)。 这只是一些 .NET 错误还是一项功能? 也许它存储了面包屑路径,也许它用于调试(尽管我在发布模式下编译)。

我该如何恢复记忆? 或者更好的是,不会因选项卡切换而丢失内存?

I have a TabControl in WPF / MVVM that is bound to an ItemsSource on top of an ObservableCollection. Each tab has its own collections and bindings with components such as Images, Richtextboxes, and user input boxes, and everything seems to work well.

However, I have noticed that each time I switch a tab, it uses about 100k of system memory which never gets reclaimed! If I hold ctrl-tab down to cycle through all tabs, I can use up 200 megs of memory within a minute.

Now - I created a blank WPF app with just a tab control, and it also uses memory for each tab switch (albiet MUCH less). Is this just some .NET bug, or a feature? Maybe it stores a breadcrumb trail, maybe its used for debugging (although I compiled in release mode).

How do I reclaim my memory? Or better yet, not lose memory to tab switchings?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拥抱我好吗 2024-08-06 17:35:01

这解决了我的问题:
http://blingcode.blogspot.com/2010/10 /memory-leak-with-wpfs-richtextbox.html

基本上为每个 RichTextBox 添加两个属性:) :)
IsUndoEnabled=“假”UndoLimit=“0”

This fixed the issue to me:
http://blingcode.blogspot.com/2010/10/memory-leak-with-wpfs-richtextbox.html

Basically add two attributes to each RichTextBox :) :)
IsUndoEnabled="False" UndoLimit="0"

っ左 2024-08-06 17:35:01

您可能想检查是否有遗留的事件处理程序。

如果您在其他控件中注册了事件,垃圾收集器将不会收集不再需要的对象,因为可以说该事件仍然附加。

因此,如果您在代码后面

public ParentEditor()
{
    InitializeComponents();
    control.Loaded += OnControlLoaded;
}

或 XAML 或 ParentControl 中的

<Control Loaded="OnControlLoaded" />

某处注册了 Loaded ,您基本上有两种解决方案来解决此问题:

解决方案 1 - 当不再需要事件处理程序时将其删除:

您可能想要删除这个处理程序在父控件的卸载中如下所示:

public ParentEditor()
{
    InitializeComponents();
    control.Loaded += OnControlLoaded;
    
    this.Unloaded += OnParentUnloaded;
}

void OnParentUnloaded(object sender, RoutedEventArgs e)
{
    //Remove unloaded event
    this.Unloaded -= OnParentUnloaded;
    
    //Remove event from child control
    control.Loaded -= OnControlLoaded;        
}

当然,您也可以使用子控件的 Unloaded 事件..这取决于您..

解决方案 2 - 使用 Wea​​kEvent 模式:

另一个事件的解决方案是 WeakEvent 模式,它绕过了这个问题。

为什么要实现 WeakEvent 模式?

监听事件可能会导致
内存泄漏。 典型技术
监听事件的方法是使用
特定于语言的语法
将处理程序附加到 a 上的事件
来源。 例如,在 C# 中,
语法是:source.SomeEvent += new
SomeEventHandler(MyEventHandler)。

这种技术创造了强大的
从事件源到事件源的引用
事件监听器。 一般情况下,附
侦听器的事件处理程序会导致
监听者有一个对象
受对象影响的寿命
源的生命周期(除非
事件处理程序被显式删除)。
但在某些情况下你可能
想要的对象生命周期
监听器只能由
其他因素,例如是否
当前属于视觉树
的应用程序,而不是由
源的生命周期。 每当
源对象的生命周期超出
侦听器的对象生命周期,
正常事件模式会导致
内存泄漏:监听器被保留
活得比预期的要长。

无论哪种情况,祝你好运..很难找到像您遇到的那样的泄漏!

You might want to check if there are any event handlers left behind.

In the case where you registered an event in other control, the garbage collector will not collect the objects that are no longer needed, because the event is still attached so to speak.

So if you registered Loaded somewhere in code behind

public ParentEditor()
{
    InitializeComponents();
    control.Loaded += OnControlLoaded;
}

or in XAML or the ParentControl

<Control Loaded="OnControlLoaded" />

You basically have two solutions to tackle this problem:

Solution 1 - Remove event handlers when they are no longer needed:

You might want to remove this handler in the unloaded of the parent control like so:

public ParentEditor()
{
    InitializeComponents();
    control.Loaded += OnControlLoaded;
    
    this.Unloaded += OnParentUnloaded;
}

void OnParentUnloaded(object sender, RoutedEventArgs e)
{
    //Remove unloaded event
    this.Unloaded -= OnParentUnloaded;
    
    //Remove event from child control
    control.Loaded -= OnControlLoaded;        
}

You can also use the Unloaded event of the child control of course.. that is up to you..

Solution 2 - Using the WeakEvent pattern:

Another solution for events would be the WeakEvent pattern, which bypasses this problem.

Why Implement the WeakEvent Pattern?

Listening for events can lead to
memory leaks. The typical technique
for listening to an event is to use
the language-specific syntax that
attaches a handler to an event on a
source. For instance, in C#, that
syntax is: source.SomeEvent += new
SomeEventHandler(MyEventHandler).

This technique creates a strong
reference from the event source to the
event listener. Ordinarily, attaching
an event handler for a listener causes
the listener to have an object
lifetime that influenced by the object
lifetime for the source (unless the
event handler is explicitly removed).
But in certain circumstances you might
want the object lifetime of the
listener to be controlled only by
other factors, such as whether it
currently belongs to the visual tree
of the application, and not by the
lifetime of the source. Whenever the
source object lifetime extends beyond
the object lifetime of the listener,
the normal event pattern leads to a
memory leak: the listener is kept
alive longer than intended.

In either case, good luck.. its quite hard to find leaks like the one you are experiencing!

我很OK 2024-08-06 17:35:01

很好的建议,但最终我认为可绑定文本块比 Richtextbox 更有用、更简单。 我从未发现是什么导致了泄漏 - 但它肯定是在 binablerichtextbox 代码中(每次切换选项卡时都会调用 OnInitialized,这超出了我的控制范围)。

泄漏消失了,并且由于使用了更简单的可绑定文本块,我的应用程序运行得更快。

Good advice, but in the end I decided a bindable textblock was more useful and simpler than a richtextbox. I never found out what was causing the leak - but it was definitely in the bindablerichtextbox code (OnInitialized was being called each time a tab switched, which was beyond my control).

The leaks are gone, and my app runs quicker because of the use of the simpler bindable textblock.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文