好吧,基本上我有这个简单的应用程序在系统托盘中运行,有一个计时器。每次勾选它都会检查给定的目录和文件是否存在,并根据结果更改其图标。
问题是每个计时器都会为应用程序内存增加~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“问题”?
答案 0 :(得分:2)
您似乎永远不会在ShowPrompt
中正确处理您的表单,所以我认为这是您的问题。
由于显示为对话框的表单未关闭,因此当您的应用程序不再需要该表单时,必须调用表单的Dispose方法。
答案 1 :(得分:2)
我将采取刺戳它是每秒发生一次的字符串连接。考虑使用StringBuilder
。虽然真的是40MB,但是40MB。
RE:您的更新。垃圾收集器正在回收它认为合适的内存。
答案 2 :(得分:1)
Garbage Collector为您完成内存管理的所有工作。 内存的临时上升并不总是意味着存在内存泄漏。当GC收集内存时,它可能会关闭。如果您怀疑存在内存泄漏,则需要进行内存分析,这不是一件容易的事。您需要阅读此article以了解可以在代码中找出问题的步骤。或者,市场上有多种工具可供您完成这项工作。您可以使用Ants Profiler红门,memprofiler等。
答案 3 :(得分:1)
可能会减少内存使用量的一些要点:
尝试预先构建您在exec()中构建的所有字符串。看起来它们都是运行时常量,但是每次打勾都要构建它们,而不是在应用程序启动时构建它们。如果无法做到这一点,请使用StringBuilder而不是+ =。
如果有更改,则仅更改控件(icon,trayText等)上的属性。 I.E.如果托盘文本已经是“[Drive C:\ - OK]”,请不要再将其值设置为“[Drive C:\ - OK]”,然后再勾选。
答案 4 :(得分:0)
您可能会考虑的一件事是,而不是使用计时器,为什么不使用FileSystemWatcher并附加到事件:
var watcher = new FileSystemWatcher("somepath");
watcher.Deleted += (sender, eventArgs) => { };
watcher.Changed += (sender, eventArgs) => { };
watcher.Error += (sender, eventArgs) => { };
watcher.Renamed += (sender, eventArgs) => { };
我也同意,一旦你完成这些表格,你应该处理这些表格。