简单的C#应用程序吞噬内存

本文关键字:吞噬 内存 应用程序 简单 | 更新日期: 2023-09-27 18:24:00

好吧,基本上我有一个简单的应用程序在有一个定时器的系统托盘中运行。每次勾选时,它都会检查给定的目录和文件是否存在,并根据结果更改其图标。

问题是,每一个计时器滴答作响,应用程序的内存就会增加约100kb。我目前让它运行大约5分钟,它已经使用了40MB的内存,这对于这样的"微型"应用程序来说是不可接受的。

这是我的代码:

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();
        }
    }
}

我已经尝试过通过将图标和图像预加载到变量中并将其分配给适当的属性来优化应用程序,但这并没有解决我的问题。

另外,请注意,我通过这样做(在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();
        }
    }
}

更新

我刚刚注意到内存使用量上升到50MB,然后下降到20MB(然后又上升)。这是我可以解决的问题还是windows的"问题"?

简单的C#应用程序吞噬内存

我将尝试一下,因为字符串串联每秒发生一次。考虑使用StringBuilder。40MB算不了什么。

回复:您的最新消息。垃圾回收器正在回收它认为合适的内存。

您似乎从未在ShowPrompt中正确处理过表单,所以我认为这是您的问题。

由于显示为对话框的窗体未关闭,因此当应用程序不再需要该窗体时,必须调用该窗体的Dispose方法。

ShowDialog

一些可以减少内存使用的要点:

尝试预构建您在exec()中构建的所有字符串。看起来它们都是运行时常量,但您可以每一次构建它们,而不是在应用程序启动时构建一次。如果这不可能,请使用StringBuilder而不是+=。

只有在发生更改时才更改控件(图标、trayText等)的属性。即,如果托盘文本已为"[Drive C:''-OK]",下一次勾选时不要将其值再次设置为"[Driver C:''-OK]"。

垃圾回收器为您完成所有内存管理工作内存暂时增加并不总是意味着内存泄漏。当GC收集内存时,它可能会下降如果怀疑内存泄漏,您需要进行内存分析,这不是一件容易的工作。您需要阅读本文,了解可以采取哪些步骤来找出代码中的问题。或者,市场上有多种工具可以为您完成这项工作。你可以使用红门的蚂蚁档案器,memprofiler等。

您可能会考虑的一件事是,与其使用计时器,为什么不使用FileSystemWatcher并附加到事件:

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

我也同意,一旦你处理完表格,你就应该把它们处理掉。