Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 简单的WPF样本会导致不受控制的内存增长_C#_Wpf_Memory Leaks - Fatal编程技术网

C# 简单的WPF样本会导致不受控制的内存增长

C# 简单的WPF样本会导致不受控制的内存增长,c#,wpf,memory-leaks,C#,Wpf,Memory Leaks,我已经将我在一个应用程序中看到的一个问题归结为一个极其简单的复制示例。我需要知道我是不是有什么地方不对劲或是我遗漏了什么 无论如何,下面是代码。其行为是,代码在内存中运行并稳定增长,直到发生OutOfMemoryException崩溃。这需要一段时间,但行为是对象正在被分配,而不是被垃圾收集 我已经把内存转储并运行了!gcroot研究了一些事情,也使用了蚂蚁来找出问题所在,但我已经研究了一段时间,需要一些新的眼睛 此复制示例是一个简单的控制台应用程序,用于创建画布并向其中添加一行。它不断地这样做

我已经将我在一个应用程序中看到的一个问题归结为一个极其简单的复制示例。我需要知道我是不是有什么地方不对劲或是我遗漏了什么

无论如何,下面是代码。其行为是,代码在内存中运行并稳定增长,直到发生OutOfMemoryException崩溃。这需要一段时间,但行为是对象正在被分配,而不是被垃圾收集

我已经把内存转储并运行了!gcroot研究了一些事情,也使用了蚂蚁来找出问题所在,但我已经研究了一段时间,需要一些新的眼睛

此复制示例是一个简单的控制台应用程序,用于创建画布并向其中添加一行。它不断地这样做。这就是代码的全部功能。它时不时地休眠,以确保CPU的负载不会导致系统无响应(并确保GC无法运行不会有任何奇怪之处)

有人有什么想法吗?我只在.NET3.0、.NET3.5和.NET3.5SP1中尝试过这种方法,在这三种环境中都出现了相同的行为

还要注意的是,我也将此代码放在WPF应用程序项目中,并在单击按钮时触发了此代码,它也出现在那里

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Controls; using System.Windows.Shapes; using System.Windows; namespace SimplestReproSample { class Program { [STAThread] static void Main(string[] args) { long count = 0; while (true) { if (count++ % 100 == 0) { // sleep for a while to ensure we aren't using up the whole CPU System.Threading.Thread.Sleep(50); } BuildCanvas(); } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void BuildCanvas() { Canvas c = new Canvas(); Line line = new Line(); line.X1 = 1; line.Y1 = 1; line.X2 = 100; line.Y2 = 100; line.Width = 100; c.Children.Add(line); c.Measure(new Size(300, 300)); c.Arrange(new Rect(0, 0, 300, 300)); } } } 使用制度; 使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用System.Windows.Controls; 使用System.Windows.Shapes; 使用System.Windows; 命名空间SimplestReproSample { 班级计划 { [状态线程] 静态void Main(字符串[]参数) { 长计数=0; while(true) { 如果(计数+++%100==0) { //睡眠一段时间以确保我们没有耗尽整个CPU 系统.线程.线程.睡眠(50); } BuildCanvas(); } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInLine)] 私有静态void BuildCanvas() { Canvas c=新画布(); 行=新行(); line.X1=1; 第1.Y1行=1; line.X2=100; 第2.Y2行=100; 线宽=100; c、 添加(行); c、 测量(新尺寸(300300)); c、 排列(新的Rect(0,0,300,300)); } } } 注意:下面的第一个答案有点离谱,因为我已经明确指出,在WPF应用程序的按钮单击事件期间,也会发生同样的行为。然而,我并没有明确指出,在那个应用程序中,我只做了有限的迭代次数(比如1000次)。这样做将允许GC在您单击应用程序时运行。还要注意的是,我明确地说我已经进行了内存转储,并发现我的对象是通过根的!根。我也不同意GC不能运行。GC不会在控制台应用程序的主线程上运行,特别是因为我在双核机器上,这意味着并发工作站GC处于活动状态。消息泵,但是,是的

为了证明这一点,这里有一个在Dispatchermer上运行测试的WPF应用程序版本。它在100毫秒的计时器间隔内执行1000次迭代。超过足够的时间来处理泵外的任何消息,并保持低CPU使用率

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Shapes; namespace SimpleReproSampleWpfApp { public partial class Window1 : Window { private System.Windows.Threading.DispatcherTimer _timer; public Window1() { InitializeComponent(); _timer = new System.Windows.Threading.DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(100); _timer.Tick += new EventHandler(_timer_Tick); _timer.Start(); } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] void RunTest() { for (int i = 0; i < 1000; i++) { BuildCanvas(); } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void BuildCanvas() { Canvas c = new Canvas(); Line line = new Line(); line.X1 = 1; line.Y1 = 1; line.X2 = 100; line.Y2 = 100; line.Width = 100; c.Children.Add(line); c.Measure(new Size(300, 300)); c.Arrange(new Rect(0, 0, 300, 300)); } void _timer_Tick(object sender, EventArgs e) { _timer.Stop(); RunTest(); _timer.Start(); } } } 使用制度; 使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用System.Windows; 使用System.Windows.Controls; 使用System.Windows.Shapes; 名称空间SimpleReploSamplewPFApp { 公共部分类Window1:Window { private System.Windows.Threading.dispatchermer\u计时器; 公共窗口1() { 初始化组件(); _计时器=new System.Windows.Threading.dispatchermer(); _timer.Interval=TimeSpan.From毫秒(100); _timer.Tick+=新事件处理程序(_timer_Tick); _timer.Start(); } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInLine)] void RunTest() { 对于(int i=0;i<1000;i++) { BuildCanvas(); } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInLine)] 私有静态void BuildCanvas() { Canvas c=新画布(); 行=新行(); line.X1=1; 第1.Y1行=1; line.X2=100; 第2.Y2行=100; 线宽=100; c、 添加(行); c、 测量(新尺寸(300300)); c、 排列(新的Rect(0,0,300,300)); } void\u timer\u Tick(对象发送方,事件参数e) { _timer.Stop(); RunTest(); _timer.Start(); } } } 注2:我使用了第一个答案的代码,我的记忆增长非常缓慢。请注意,1ms比我的示例慢得多,迭代次数也少。在你开始注意到增长之前,你必须让它运行几分钟。5分钟后,从30MB的起点到46MB


注3:删除对.Arrange的调用将完全消除增长。不幸的是,这个调用对我的使用非常重要,因为在许多情况下,我是从画布(通过RenderTargetBitmap类)创建PNG文件的。如果不调用.Arrange,它根本不会布局画布。

编辑2:显然不是答案,但它是这里答案和评论之间来回的一部分,因此我不会删除它

GC永远没有机会收集这些对象,因为循环及其阻塞调用永远不会结束,因此消息泵和事件永远不会轮到它们。如果您使用某种类型的
计时器
,以便消息和事件实际上有机会进行处理,您可能无法耗尽所有时间
public partial class Window1 : Window {
    Class1 c;
    DispatcherTimer t;
    int count = 0;
    public Window1() {
        InitializeComponent();

        t = new DispatcherTimer();
        t.Interval = TimeSpan.FromMilliseconds( 1 );
        t.Tick += new EventHandler( t_Tick );
        t.Start();
    }

    void t_Tick( object sender, EventArgs e ) {
        count++;
        BuildCanvas();
    }

    private static void BuildCanvas() {
        Canvas c = new Canvas();

        Line line = new Line();
        line.X1 = 1;
        line.Y1 = 1;
        line.X2 = 100;
        line.Y2 = 100;
        line.Width = 100;
        c.Children.Add( line );

        c.Measure( new Size( 300, 300 ) );
        c.Arrange( new Rect( 0, 0, 300, 300 ) );
    }
}
c.UpdateLayout()
public partial class App : Application
{
   public App() 
   { 
       new HwndSource(new HwndSourceParameters()); 
   } 
}