简体   繁体   English

简单的C#应用​​程序吃掉内存

[英]Simple C# application eating memory

Alright so basicly I have this simple application running in system tray that has one timer. 好吧,基本上,我在具有一个计时器的系统托盘中运行了这个简单的应用程序。 Every tick it performs a check to see if a given directory and file exists, and based on the result it changes its icon. 每次打勾时,它都会检查以查看给定的目录和文件是否存在,并根据结果更改其图标。

The problem is every single timer tick the memory for the application raises ~100kb. 问题在于,每个计时器都会为应用程序的内存增加约100kb。 I currently have it running for about 5 mins and it already uses 40MB of memory, which is unacceptable for such "micro" application. 我目前正在运行它大约5分钟,它已经使用了40MB的内存,这对于这种“微型”应用程序是不可接受的。

Here's my code: 这是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace Tray
{
    public partial class Main : Form
    {
        string drive = "C:\\";
        string file  = "test.txt";

        System.Drawing.Image imgRed     = Image.FromFile("res\\icon-red.png");
        System.Drawing.Image imgOrange  = Image.FromFile("res\\icon-orange.png");
        System.Drawing.Image imgGreen   = Image.FromFile("res\\icon-green.png");
        System.Drawing.Icon  icoRed      = System.Drawing.Icon.ExtractAssociatedIcon("res\\icon-red.ico");
        System.Drawing.Icon  icoOrange   = System.Drawing.Icon.ExtractAssociatedIcon("res\\icon-orange.ico");
        System.Drawing.Icon  icoGreen    = System.Drawing.Icon.ExtractAssociatedIcon("res\\icon-green.ico");

        public Main()
        {
            InitializeComponent();
        }

        public static string ShowPrompt(string text, string caption)
        {
            Form prompt = new Form();
            prompt.Width = 500;
            prompt.Height = 150;
            prompt.Text = caption;
            Label textLabel = new Label() { Left = 50, Top = 20, Text = text };
            TextBox textBox = new TextBox() { Left = 50, Top = 50, Width = 400 };
            Button confirmation = new Button() { Text = "Ok", Left = 350, Width = 100, Top = 70 };
            confirmation.Click += (sender, e) => { prompt.Close(); };
            prompt.Controls.Add(confirmation);
            prompt.Controls.Add(textLabel);
            prompt.Controls.Add(textBox);
            prompt.ShowDialog();
            return textBox.Text;
        }

        public void updateInfo(){
            this.statusDrive.Text = "Drive [" + drive + "]";
            this.statusFile.Text = "File [" + drive + file + "]";
        }

        public void exec(){
            int status = 0;

            this.trayIcon.Text = "[Drive - ";
            if (Directory.Exists(drive)){
                this.statusDrive.Text += " - OK";
                this.statusDrive.Image = imgGreen;
                status++;
                this.trayIcon.Text += "OK] ";
            } else{
                this.statusDrive.Text += " - FAIL";
                this.statusDrive.Image = imgRed;
                this.trayIcon.Text += "FAIL] ";
            }

            this.trayIcon.Text += "[File - ";
            if (File.Exists(drive + file))
            {
                this.statusFile.Text += " - OK";
                this.statusFile.Image = imgGreen;
                status++;
                this.trayIcon.Text += "OK] ";
            }
            else
            {
                this.statusFile.Text += " - FAIL";
                this.statusFile.Image = imgRed;
                this.trayIcon.Text += "FAIL] ";
            }

            switch (status)
            {
                case 2:
                    this.Icon = icoGreen;
                    this.trayIcon.Icon = icoGreen;
                    this.status.Image = imgGreen;
                    break;
                case 1:
                    this.Icon = icoOrange;
                    this.trayIcon.Icon = icoOrange;
                    this.status.Image = imgOrange;
                    break;
                case 0:
                default:
                    this.Icon = icoRed;
                    this.trayIcon.Icon = icoRed;
                    this.status.Image = imgRed;
                    break;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Hide();

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            updateInfo();
            exec();
        }

        private void chDrive_Click(object sender, EventArgs e)
        {
            this.drive = ShowPrompt("Enter drive path", "Change drive");
        }

        private void chFile_Click(object sender, EventArgs e)
        {
            this.file = ShowPrompt("Enter new file path:", "Change file");
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

I already tried to optimize the app by preloading the icons and images into variables and assigning those to the appropriate properties, however this didn't solve my problem. 我已经尝试通过将图标和图像预加载到变量中并将它们分配给适当的属性来优化应用程序,但是这并不能解决我的问题。

Also, note that I managed to hide my main window by doing this (in Program.cs): 另外,请注意,通过执行以下操作(在Program.cs中),我设法隐藏了主窗口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace Tray
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Main mForm = new Main();
            Application.Run();
        }
    }
}

UPDATE 更新

I just noticed that the memory usage climbs up to 50MB and drops to 20MB afterwards (and goes up again). 我只是注意到内存使用量上升到50MB,然后下降到20MB(然后又上升)。 Is this something I can possibly address or is it a windows "issue"? 这是我可能解决的问题,还是Windows的“问题”?

You never appear to be disposing your form correctly in ShowPrompt , so I'd imagine this is your problem. 您似乎从来没有在ShowPrompt正确地ShowPrompt ,所以我想这是您的问题。

Because a form displayed as a dialog box is not closed, you must call the Dispose method of the form when the form is no longer needed by your application. 因为未关闭显示为对话框的表单,所以当应用程序不再需要该表单时,必须调用该表单的Dispose方法。

ShowDialog 显示对话框

I'm going to take a stab at it being the string concatenations happening once a second. 我要刺痛一下,它是每秒发生一次字符串串联。 Consider using a StringBuilder . 考虑使用StringBuilder 40MB is nothing though really. 40MB确实不是什么。

RE: Your update. RE:您的更新。 The Garbage Collector is reclaiming the memory as it sees fit. 垃圾收集器正在回收它认为合适的内存。

Garbage Collector does all the work of memory management for you. 垃圾收集器将为您完成所有内存管理工作。 Temporary rise in memory doesn't always mean that there is a memory leak. 内存的临时增加并不总是意味着内存泄漏。 It may come down when the GC collects memory. GC收集内存时,它可能会下降。 In case you suspect that there are memory leaks you need to do memory profiling which is no easy job. 如果您怀疑内存泄漏,则需要进行内存分析,这并非易事。 You need to read into this article for steps that you can take to find out the problem in your code. 您需要阅读本文以获取可用来发现代码中问题的步骤。 Alternatively, there are multiple tools avaiable in the market to do this job for you. 或者,市场上有多种工具可以为您完成这项工作。 You can use Ants Profiler of Red Gate, memprofiler amongst others. 您可以使用Red Gate的Ants Profilermemprofiler等。

Some points that could cut down on memory usage: 可能会减少内存使用的一些要点:

Try to prebuild all those strings you're building in exec(). 尝试预构建您正在exec()中构建的所有那些字符串。 It looks like they're all runtime constants, but you build them every tick instead of building them once when the application starts. 看起来它们都是运行时常量,但是您在每个滴答声中都构建它们,而不是在应用程序启动时构建它们。 If this isn't possible, use StringBuilder instead of +=. 如果不可能,请使用StringBuilder而不是+ =。

Only change properties on controls (icon, trayText, etc) if there has been a change. 仅在发生更改的情况下更改控件的属性(图标,trayText等)。 IE if tray text is already "[Drive C:\\ - OK]", don't set its value again to "[Drive C:\\ - OK]" next tick. IE,如果纸盘文本已经是“ [Drive C:\\-OK]”,则不要在下一个刻度上再次将其值设置为“ [Drive C:\\-OK]”。

One thing you might consider is rather than using a timer why not use the FileSystemWatcher and attach to events: 您可能会考虑的一件事不是使用计时器,而是为什么不使用FileSystemWatcher并附加到事件:

var watcher = new FileSystemWatcher("somepath");
watcher.Deleted += (sender, eventArgs) => { };
watcher.Changed += (sender, eventArgs) => { };
watcher.Error += (sender, eventArgs) => { };
watcher.Renamed += (sender, eventArgs) => { };

I also agree that you should be disposing of the forms once you're done with them. 我也同意,一旦处理完表格,就应该将其丢弃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM