c#绘图程序 内存占用巨大,求解决
小弟正在上的一门课,做一个类似MS 画图的程序,老师讲的代码中,利用双缓冲绘图时会闪烁,拼接了网上的一些代码,解决了闪烁的问题,但是内存的占用却直线飙升,最高达到300M,一个28k的小程序占用这么多内存,汗。。。求高手指点一二(初学,水平有限,高手勿喷)
namespace pencil--------------------编程问答-------------------- 内存飙升可能是因为内存泄露,代码太长,很难看,最好用工具来分析, --------------------编程问答-------------------- 代码好多啊,,,, --------------------编程问答-------------------- 有些资源要及时释放掉
{
public partial class FormMain : Form
{
//声明canmove以判定是否绘制
public bool CanMove = false;
//当前画笔的线宽
public int DrawPenWidth = 5;
//画笔的颜色
public Color DrawPenColor = Color.Red;
public Image FinishImg;
//定义窗口绘图对象
public Graphics WndGraphics = null;
//画笔
private Pen _pen = null;
//双缓冲技术的位图
public Bitmap Bitmap = null;
//与位图相关的绘图对象
public Graphics BitmapGraphics = null;
public List<Shape> _listShape = new List<Shape>();
//保存绘图类型,默认为直线
public OperationType _OperationType = OperationType.Line;
public FormMain()
{
InitializeComponent();
}
//菜单内各个选项的响应事件
//直线
private void MenuItemLine_Click(object sender, EventArgs e)
{
_OperationType = OperationType.Line;
}
//矩形
private void MenuItemRectangle_Click(object sender, EventArgs e)
{
_OperationType = OperationType.Rectangle;
}
//圆
private void MenuItemCircle_Click(object sender, EventArgs e)
{
_OperationType = OperationType.Circle;
}
//停止
private void MenuItemStop_Click(object sender, EventArgs e)
{
this.Close();
}
//曲线
private void MenuItemCurve_Click(object sender, EventArgs e)
{
_OperationType = OperationType.Curve;
}
//鼠标下压的响应事件
private void FormMain_MouseDown(object sender, MouseEventArgs e)
{
if (_OperationType == OperationType.Line)
{
//保存直线的起点
Line templine = new Line();
templine._Point1 = new Point(e.X, e.Y);
//将起点存入链表
_listShape.Add(templine);
}
else if (_OperationType == OperationType.Rectangle)
{
//保存矩形的起点
Rectangle tempRec = new Rectangle();
tempRec._Point1 = new Point(e.X, e.Y);
_listShape.Add(tempRec);
}
else if (_OperationType == OperationType.Circle)
{
//保存圆心
Circle circle = new Circle();
circle._Center = new Point(e.X, e.Y);
_listShape.Add(circle);
}
else if (_OperationType == OperationType.Curve)
{
//FinishImg = (Image)Bitmap.Clone();
//将move设置为true,以检测move值确定是否终止
CanMove = true;
//创建曲线对象
Line curve = new Line();
//保存曲线的第一个点
curve._Point1 = new Point(e.X, e.Y);
_listShape.Add(curve);
}
}
//绘制曲线时鼠标移动的响应事件
private void FormMain_MouseMove(object sender, MouseEventArgs e)
{
this.Text = string.Format("X:{0},Y:{1}", e.X, e.Y);
if (e.Button == MouseButtons.Left)
{
if (_OperationType != OperationType.Curve)
{
FinishImg =new Bitmap(Bitmap);
WndGraphics = Graphics.FromImage(FinishImg);
WndGraphics.SmoothingMode = SmoothingMode.AntiAlias;
}
if (_OperationType == OperationType.Curve && CanMove == true)
{
Graphics g1 = Graphics.FromImage(FinishImg);
g1.SmoothingMode = SmoothingMode.AntiAlias;
//确定第二个点并绘制直线
g1.DrawLine(_pen, ((Line)_listShape[_listShape.Count - 1])._Point1, new Point(e.X, e.Y));
//将point2赋给point1,继续移动鼠标,绘制第二个点与第三个点之间的直线,以此类推
((Line)(_listShape[_listShape.Count - 1]))._Point1 = new Point(e.X, e.Y);
g1.Dispose();
}
else if (_OperationType == OperationType.Line)
{
WndGraphics.DrawLine(_pen, ((Line)_listShape[_listShape.Count - 1])._Point1, new Point(e.X, e.Y));
}
else if (_OperationType == OperationType.Rectangle)
{
//将第一个点存入临时点中
Point tempPoint = ((Rectangle)_listShape[_listShape.Count - 1])._Point1;
Point leftTop = new Point();
//确定左上角的点横纵坐标
leftTop.X = (tempPoint.X < e.X) ? tempPoint.X : e.X;
leftTop.Y = (tempPoint.Y < e.Y) ? tempPoint.Y : e.Y;
//绘制矩形
WndGraphics.DrawRectangle(_pen, leftTop.X, leftTop.Y, Math.Abs(tempPoint.X - e.X), Math.Abs(tempPoint.Y - e.Y));
}
else if (_OperationType == OperationType.Circle)
{
//取出圆心
Point center = ((Circle)_listShape[_listShape.Count - 1])._Center;
//以像素填充法突出显示圆心,二三个参数为圆心坐标,四五个参数为填充像素的大小
WndGraphics.FillRectangle(new SolidBrush(Color.Red), center.X, center.Y, 3, 3);
//圆的半径
float R = (float)Math.Sqrt(Math.Pow((e.X - center.X), 2) + Math.Pow((e.Y - center.Y), 2));
//绘制
WndGraphics.DrawEllipse(_pen, center.X - R, center.Y - R, 2 * R, 2 * R);
}
}
WndGraphics.Dispose();
reDraw(FinishImg);
}
private void reDraw(Image img)
{
Graphics graphics = this.CreateGraphics();
//graphics = this.CreateGraphics();
//重绘
graphics.DrawImage(img, 0, 0);
graphics.Dispose();
}
//鼠标松开的响应事件
private void FormMain_MouseUp(object sender, MouseEventArgs e)
{
//直线
if (_OperationType == OperationType.Line)
{
//保存终点
((Line)(_listShape[_listShape.Count - 1]))._Point2 = new Point(e.X, e.Y);
_listShape[_listShape.Count - 1].Draw(BitmapGraphics);
}
//矩形
else if (_OperationType == OperationType.Rectangle)
{
((Rectangle)(_listShape[_listShape.Count - 1]))._Point2 = new Point(e.X, e.Y);
_listShape[_listShape.Count - 1].Draw(BitmapGraphics);
}
//圆
else if (_OperationType == OperationType.Circle)
{
//圆心
Point center = ((Circle)_listShape[_listShape.Count - 1])._Center;
//圆的半径
((Circle)(_listShape[_listShape.Count - 1]))._R =
(float)Math.Sqrt(Math.Pow((e.X - center.X), 2) + Math.Pow((e.Y - center.Y), 2));
//绘制
_listShape[_listShape.Count - 1].Draw(BitmapGraphics);
}
//曲线
if (_OperationType == OperationType.Curve)
{
//将move设置为false,鼠标移动是不再响应
CanMove = false;
}
//WndGraphics.DrawImage(Bitmap, 0, 0);
Bitmap = (Bitmap)FinishImg;
}
private void FormMain_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(Bitmap, 0, 0);
}
//清空画板
private void MenuItemClear_Click(object sender, EventArgs e)
{
WndGraphics.Clear(Color.White);
}
private void FormMain_Load(object sender, EventArgs e)
{
//创建窗体画笔对象和绘图对象
WndGraphics = this.CreateGraphics();
_pen = new Pen(DrawPenColor, DrawPenWidth);
//创建双缓冲技术的位图,其大小与屏幕大小相同
Bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
//创建与缓冲位图相关的绘图对象
BitmapGraphics = Graphics.FromImage(Bitmap);
BitmapGraphics.Clear(Color.White);
//防止出现锯齿
BitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
this.UpdateStyles();
FinishImg = (Image)Bitmap;
this.BackgroundImage = Bitmap;
}
//关闭窗体,释放资源
private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
{
//释放资源,防止内存泄露
WndGraphics.Dispose();
Bitmap.Dispose();
BitmapGraphics.Dispose();
}
private void FormMain_Resize(object sender, EventArgs e)
{
//resize保证画图区随窗体的大小变化而变化
WndGraphics = this.CreateGraphics();
}
//设置画笔颜色
private void MenuItemColor_Click(object sender, EventArgs e)
{
//默认选中当前颜色
colorDialogPen.Color = DrawPenColor;
//点击确定,存储用户选择的颜色
if (colorDialogPen.ShowDialog() == DialogResult.OK)
{
DrawPenColor = colorDialogPen.Color;
//设置画笔颜色
_pen.Color = DrawPenColor;
}
}
//设置画笔线宽
private void MenuItemWidth_Click(object sender, EventArgs e)
{
//创建对话框
DialogPenWidth dialogPenWidth = new DialogPenWidth();
//显示上一次的线宽
dialogPenWidth.textBoxWidth.Text = DrawPenWidth.ToString();
//获取设置的线宽
if (dialogPenWidth.ShowDialog() == DialogResult.OK)
{
DrawPenWidth = Convert.ToInt32(dialogPenWidth.textBoxWidth.Text);
_pen.Width = DrawPenWidth;
}
}
}
}
--------------------编程问答-------------------- 每次绘制完毕都释放一次旧图。或者定义一个全局的画布,每次重新绘制前先释放掉旧的画布。 --------------------编程问答-------------------- 只看到_listShape.Add,存这么多点干嘛用啊 --------------------编程问答-------------------- 用工具测一下,代码这么长~ --------------------编程问答-------------------- 请将Graphic对象放到方法中创建,然后销毁,不要有全局的Graphic对象,试试。 --------------------编程问答-------------------- 没用的Bitmap对象使用完后要调用dispose,释放掉! --------------------编程问答-------------------- 确认了一下,问题就出在bitmap转成image这里了(第102行),但是不会改, --------------------编程问答-------------------- 确认了一下,问题就出在bitmap转成image这里了(第102行),但是不会改, --------------------编程问答-------------------- FinishImg 和 Bitmap 这两个变量是什么关系,直接等于不行吗?
//FinishImg =new Bitmap(Bitmap);
FinishImg = Bitmap; --------------------编程问答-------------------- 直接等于的话,鼠标松开之前绘制的轨迹就不会被擦除了,每移动一次鼠标的绘制都会画出来 --------------------编程问答-------------------- 你在reDraw(FinishImg);后面,没有将FinishImg对象释放,这个FinishImg不手动释放,内存就不会被释放的。 --------------------编程问答-------------------- 你只在窗口关闭事件里面用了释放资源,一直一直画图,不关闭窗口的,你想想你的内存会被占用多少资源 --------------------编程问答--------------------
是的,那你FinishImg要先释放
if(FinishImg!=null)
{
FinishImg.Dispose();
FinishImg =null;
}
FinishImg =new Bitmap(Bitmap); --------------------编程问答-------------------- 运行直接报错。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 是什么时候内存井喷了,是页面加载的时候吗,先定位好问题 --------------------编程问答-------------------- 除
补充:.NET技术 , C#