【问题标题】:PowerPoint VSTO allocates more and more memoryPowerPoint VSTO 分配的内存越来越多
【发布时间】:2020-09-13 17:37:27
【问题描述】:

我正在编写一个 VSTO,它遍历所有幻灯片、所有形状并将标题设置为一个值。 我认识到每次运行后内存消耗都会增加。 因此,我最小化了我的代码并让它运行 100 次,最终为每 100 次运行分配大约 20MB 内存。

我的代码是从侧边栏按钮执行的,演示文稿有大约 30 张带标题的幻灯片。 我的按钮代码如下所示:

        private void button1_Click(object sender, EventArgs e)
    {
        SetTitle_Direct();

        Stopwatch watch = new Stopwatch();
        watch.Start();

        SetTitle_Direct();

        watch.Stop();
        //MessageBox.Show("Time spend: " + watch.Elapsed);

        AMRefreshProgress.Maximum = 100;
        AMRefreshProgress.Step = 1;
        AMRefreshProgress.UseWaitCursor = true;
        AMRefreshProgress.ForeColor = System.Drawing.ColorTranslator.FromHtml(ThisAddIn.amColor);


        for (int i = 1; i <= 100; i++)
        {
            SetTitle_Direct();
            AMRefreshProgress.PerformStep();
        }


        AMRefreshProgress.Value = 0;
        AMRefreshProgress.UseWaitCursor = false;


        Stopwatch watch2 = new Stopwatch();
        watch2.Start();

        SetTitle_Direct();

        watch2.Stop();
        MessageBox.Show("Time 1st run: " + watch.Elapsed + "\n Time 11th run: " + watch2.Elapsed);
    }

SetTitle_Direct() 循环遍历幻灯片:

        public void SetTitle_Direct()
    {
        PowerPoint.Presentation oPresentation = Globals.ThisAddIn.Application.ActivePresentation;

        foreach (PowerPoint.Slide oSlide in oPresentation.Slides)
        {

            if (oSlide.Shapes.HasTitle == OFFICECORE.MsoTriState.msoTrue)
            {
                oSlide.Shapes.Title.TextFrame.TextRange.Text = "Test Main Title";
            }



            for (int iShape = 1; iShape <= oSlide.Shapes.Count; iShape++)
            {
                if (oSlide.Shapes[iShape].Type == Microsoft.Office.Core.MsoShapeType.msoPlaceholder)
                {
                    if (oSlide.Shapes[iShape].PlaceholderFormat.Type == PowerPoint.PpPlaceholderType.ppPlaceholderSubtitle)
                    {
                        oSlide.Shapes[iShape].TextFrame.TextRange.Text = "Test Sub Title";
                    }
                }
            }
        }
    }

是什么导致插件分配越来越多的内存 - 或者如何避免这种情况?

【问题讨论】:

    标签: memory vsto powerpoint


    【解决方案1】:

    当您开发基于 VSTO 的加载项时,您通常会处理 COM 对象(PowerPoint 是一个 COM 服务器)。对于每个返回 COM 对象的属性或方法调用,对象引用通常会增加,这会导致将对象保留在内存中,直到引用计数器减少并等于零。因此,我建议使用Marshal.ReleaseComObject 方法来减少对象引用并让运行时保留内存并缩短对象的生命周期。

    为了能够释放每个 COM 对象,您必须拆分长行的属性和方法调用。在单独的代码行上声明每个属性或方法调用。因此,如果发生任何奇怪的事情,您将能够释放每个对象并有效地调试代码。

    您可以查看When to release COM objects in Office add-ins developed in .NET 文章了解更多信息。

    另一种方法是使用垃圾收集器:

    GC.Collect
    GC.WaitForPendingFinalizers
    GC.Collect
    GC.WaitForPendingFinalizers
    

    【讨论】:

    • 感谢您的回答。就我而言,如何正确实施?我在 SetTitle_Direct() Marshal.ReleaseComObject(oPresentation); 中添加了类似的内容但是内存使用率仍然上升,每次运行都变得越来越慢。如何预防这种行为?
    • 尝试使用垃圾收集器:GC.Collect GC.WaitForPendingFinalizers GC.Collect GC.WaitForPendingFinalizers
    • 我已经按照建议添加了垃圾收集器——还有 Marshal.ReleaseComObject(oPresentation)——但没有任何帮助。当我启动 Powerpoint 并添加内存在 3 次运行上述代码 33 张幻灯片后的使用量为 220MB(进程内存)时,“进程内存”为 320MB,并且在所有幻灯片中运行一次比第一次慢 5 倍.在上面的代码中,插入 Marshal.ReleaseComObject 和垃圾收集器的正确位置在哪里?系统释放内存需要多长时间?如何减少 obj 的生命周期?
    • 似乎对象指针仍然有效。在运行 GC 之前将它们设置为 Nothing
    • 你的意思是“将它们设置为空”:oPresentation = null; Marshal.ReleaseComObject(oPresentation); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers();
    猜你喜欢
    • 2012-09-15
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多