none
加载Picture内存不释放 RRS feed

  • 问题

  • 自从C#一产生,我就认为它很优美,到现在除了它漂亮外,我也不知它能作什么? 做个图像,加载到Picture占用内存一直占下去,不释放,不象Delphi,C++等来个Free,Delete 可以见到内存马上减小

    来看一下呢,可以帮我改一下代码吗?

    我的图片文件有30M的样子

    Bitmap bit = null;

    //两个按钮交替点击N次,内存会占到几百M,吓人呢?

    private void toolStripButton1_Click(object sender, EventArgs e)

    {

    pictureBox1.Image = null;

    bit=new Bitmap(@"c:\2\a.bmp");

    pictureBox1.Image = bit;

    }

    private void toolStripButton2_Click(object sender, EventArgs e)

    {

    pictureBox1.Image = null;

    bit=new Bitmap("c:\\1\\b.jpg");

    pictureBox1.Image = bit;

    }


    2011年10月9日 15:51

答案

  • .NET 的内存释放是有GC完成的。

    不需要你自己管理,这么说来,好比你住c或者delphi的旅馆,你必须自己洗衣服,而你住ms的。net旅馆,你只需要把衣服扔到外面,自然后GC大妈帮你洗好,在你需要的时候给你送来。


    family as water
    2011年10月10日 0:32
  • 用C#,你需要把自己看成一个领袖

    至于内存管理这种低级的事情,不是一个当领袖的人应该去管的.

     

    比如,古德里安,我完全相信他开一辆坦克,要比绝大多数德国坦克兵开得帅

    但身为五星上将,更应该考虑的是如何部署调动几百上千辆坦克

    这远比把一辆坦克开得好要产生出大得多的价值

     

    我相信,你在更高级别上产生的价值也要远比操纵更好几M的内存要多得多

    2011年10月10日 6:57
  • 楼主您的代码本身就会造成内存泄漏。因为 Bitmap 是一个系统资源,是 Windows 的 HBITMAP 包装来的,您必须调用 Dispose() 释放这个资源,否则 Windows 一直为它保留内存。

    注意  bitmap = null 这句话只是将 bitmap 这个变量的引用清掉了,而不是把它占的内存释放掉了。

    不是说 CLR 有了 GC 您就什么事情都不用做了,您要 use GC wisely. 特别是有操作系统资源时。比如 IO,GDI,注册表,网络等。在使用一个类型时,先看看它是否实现了 IDisposable 接口,有的,则必须用 using 语句用完他后立即回收掉。

    另外我想反驳一下这个标题,要知道现在开发者使用的 70% 以上的软件,都使用了 .NET Framework。包括 Windows 自己,还有 Visual Studio,SQL Server 等。不是说 C# 中看不中用,是看您如何用。


    Mark Zhou
    2011年10月10日 8:55
  • dear

    天~并非使用null就是释放,你必须对物件呼叫Close()或Dispose()方法,要改善代码必须要对C#语言以及.NET CLR有相当程度了解,若单纯只是要了解.NET CLR你可参考以下

    CLR via C#(第3版)/微軟技術叢書 (for .net 4.0)
    http://tl.zxhsd.com/kgsm/ts/big5/2010/09/21/1826692.shtml

    框架設計<第2版>--CLR Via C#/微軟技術叢書 (for .net 2.0)
    http://tl.zxhsd.com/kgsm/ts/big5/2008/12/16/1013003.shtml

    若要使用设计模式来优化代码,可参考程杰老师所写的大话设计模式
    http://tl.zxhsd.com/kgsm/ts/big5/2008/12/16/1219546.shtml


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2011年10月10日 16:43
  • 那我觉得真的是你的图片太大了。

    可以试一下 在加载之前,先把 pictureBox1.Image 给释放掉,然后再赋值给它。

     private void toolStripButton1_Click(object sender, EventArgs e)
            {
                pictureBox1.Image.Dispose();
                currentIndex = currentIndex > PictureList.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
               // Console.WriteLine(PictureList[currentIndex].ToString());
            }
    
            private void toolStripButton2_Click(object sender, EventArgs e)
            {
                pictureBox1.Image.Dispose();
                currentIndex = currentIndex > PictureList.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
               // Console.WriteLine(PictureList[currentIndex].ToString());
            }
    

    在我的电脑(Visual Studio 2010,.Net Framework 4.0,Windows 7)上测试是没有问题的。用这种办法可以见到成效的。希望对您有用。


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月13日 1:46
    版主
  • 首先你得确定pictureBox1.Image 不为空,然后才能释放掉。

    建议你可以加个if 条件判断:

       if (pictureBox1.Image != null)
                {
                    //先释放掉,然后加载
                }
                else
                {
                    //加载图片
                }
    


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月14日 1:23
    版主
  • .Net 中的GC是不定时触发的和隐式执行。只要内存足够使用,他就不会被触发。

    但是我们可以显示的指定GC执行,前面有提到的GC.Collect()。

     


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月17日 2:04
    版主

全部回复

  • .NET 的内存释放是有GC完成的。

    不需要你自己管理,这么说来,好比你住c或者delphi的旅馆,你必须自己洗衣服,而你住ms的。net旅馆,你只需要把衣服扔到外面,自然后GC大妈帮你洗好,在你需要的时候给你送来。


    family as water
    2011年10月10日 0:32
  • 用C#,你需要把自己看成一个领袖

    至于内存管理这种低级的事情,不是一个当领袖的人应该去管的.

     

    比如,古德里安,我完全相信他开一辆坦克,要比绝大多数德国坦克兵开得帅

    但身为五星上将,更应该考虑的是如何部署调动几百上千辆坦克

    这远比把一辆坦克开得好要产生出大得多的价值

     

    我相信,你在更高级别上产生的价值也要远比操纵更好几M的内存要多得多

    2011年10月10日 6:57
  • 楼主您的代码本身就会造成内存泄漏。因为 Bitmap 是一个系统资源,是 Windows 的 HBITMAP 包装来的,您必须调用 Dispose() 释放这个资源,否则 Windows 一直为它保留内存。

    注意  bitmap = null 这句话只是将 bitmap 这个变量的引用清掉了,而不是把它占的内存释放掉了。

    不是说 CLR 有了 GC 您就什么事情都不用做了,您要 use GC wisely. 特别是有操作系统资源时。比如 IO,GDI,注册表,网络等。在使用一个类型时,先看看它是否实现了 IDisposable 接口,有的,则必须用 using 语句用完他后立即回收掉。

    另外我想反驳一下这个标题,要知道现在开发者使用的 70% 以上的软件,都使用了 .NET Framework。包括 Windows 自己,还有 Visual Studio,SQL Server 等。不是说 C# 中看不中用,是看您如何用。


    Mark Zhou
    2011年10月10日 8:55
  • 如何完善这一代码呢??
    2011年10月10日 16:25
  • dear

    天~并非使用null就是释放,你必须对物件呼叫Close()或Dispose()方法,要改善代码必须要对C#语言以及.NET CLR有相当程度了解,若单纯只是要了解.NET CLR你可参考以下

    CLR via C#(第3版)/微軟技術叢書 (for .net 4.0)
    http://tl.zxhsd.com/kgsm/ts/big5/2010/09/21/1826692.shtml

    框架設計<第2版>--CLR Via C#/微軟技術叢書 (for .net 2.0)
    http://tl.zxhsd.com/kgsm/ts/big5/2008/12/16/1013003.shtml

    若要使用设计模式来优化代码,可参考程杰老师所写的大话设计模式
    http://tl.zxhsd.com/kgsm/ts/big5/2008/12/16/1219546.shtml


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2011年10月10日 16:43
  • 像Stone,AceBear,Mark Zhou, 余小章所说的一样,.Net 中有自己的垃圾回收机制--GC。

    http://msdn.microsoft.com/zh-cn/library/0xy59wtx.aspx

    一般情况下,GC是隐式执行,但他又允许我们显示调用去释放不需要的对象内存:

     GC.Collect();
    

    或许您的代码这样修改会好点:

         private void button4_Click(object sender, EventArgs e)
            {
                pictureBox1.Image = null;
                Bitmap bit = new Bitmap(@"D:\rocky's files\pic\Myslelf.jpg");
                pictureBox1.Image = bit;
                GC.Collect();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                pictureBox1.Image = null;
                Bitmap bit = new Bitmap(@"D:\rocky's files\pic\Myslelf.jpg");
                pictureBox2.Image = bit;
                GC.Collect();
            }
    

    _希望帮得到您。


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月11日 5:45
    版主
  • 不行呀,内存占用居高不下,查看一下磁盘的N个图片有这么难吗??是C#错了,还是我错了,如果是我错了,错在哪里??
    2011年10月11日 13:44
  • 我用这段代码测试,每次运行占用的内存都在3M左右。我有2900多张图片,大概在22M左右。

      List<string> PictureList = new List<string>();
            int currentIndex = -1;
    
    
            private void button2_Click(object sender, EventArgs e)
            {
                currentIndex = currentIndex > PictureList.Count - 2 ? 0 : ++currentIndex;
               pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
    
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                PictureList.AddRange(System.IO.Directory.GetFiles(@"D:\rocky's files\pic", "*.jpg"));
                if (PictureList.Count > 0)
                {
                    currentIndex = 0;
                    string picName = "(" + currentIndex + ")";
                    pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
                }
    
            }
    

    您可以试一下。


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月12日 2:03
    版主
  • 你的方法不行呢,浏览文件夹下的图片,内存占用增加到出现内存不足的错误呢?      

    private void toolStripButton1_Click(object sender, EventArgs e)
            {
                currentIndex = currentIndex > picturelist.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image=Image.FromFile(picturelist[currentIndex]);
            }

            private void toolStripButton2_Click(object sender, EventArgs e)
            {
                currentIndex = currentIndex > picturelist.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image = Image.FromFile(picturelist[currentIndex]);
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                picturelist.AddRange(Directory.GetFiles("c:\\1", "*.jpg"));
                if (picturelist.Count > 0)
                {
                    currentIndex = 0;
                    string picName = "(" + currentIndex + ")";
                    pictureBox1.Image = Image.FromFile(picturelist[currentIndex]);
                }

            }

    2011年10月12日 14:50
  • 那我觉得真的是你的图片太大了。

    可以试一下 在加载之前,先把 pictureBox1.Image 给释放掉,然后再赋值给它。

     private void toolStripButton1_Click(object sender, EventArgs e)
            {
                pictureBox1.Image.Dispose();
                currentIndex = currentIndex > PictureList.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
               // Console.WriteLine(PictureList[currentIndex].ToString());
            }
    
            private void toolStripButton2_Click(object sender, EventArgs e)
            {
                pictureBox1.Image.Dispose();
                currentIndex = currentIndex > PictureList.Count - 2 ? 0 : ++currentIndex;
                pictureBox1.Image = Image.FromFile(PictureList[currentIndex]);
               // Console.WriteLine(PictureList[currentIndex].ToString());
            }
    

    在我的电脑(Visual Studio 2010,.Net Framework 4.0,Windows 7)上测试是没有问题的。用这种办法可以见到成效的。希望对您有用。


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月13日 1:46
    版主
  • 如果我不是从磁盘加载图片,是从数据库中读取图片,用Dispose会找不到实例呢》?


            private void VreadImage()
            {
                SqlConnection cn = LinkDB.LinkDBSqlconnection(cnstr);
                if (cn.State == ConnectionState.Closed) cn.Open();
                string cmdstr = "select cardImage from CardImage where autoid=" +
                    recordNo;               
                SqlCommand cmd = new SqlCommand(cmdstr, cn);
                Byte[] b = (Byte[])cmd.ExecuteScalar(); 
                if (b.Length > 0)
                {
                    MemoryStream ms = new MemoryStream(b, true);               
                    ms.Write(b, 0, b.Length);
                 
                    //pictureBox1.Image.Dispose();//有了这句会出错的???              
                    this.pictureBox1.Image = Image.FromStream(ms);               
                    ms.Dispose();
                }
                cn.Dispose();
            }

    2011年10月13日 15:10
  • 首先你得确定pictureBox1.Image 不为空,然后才能释放掉。

    建议你可以加个if 条件判断:

       if (pictureBox1.Image != null)
                {
                    //先释放掉,然后加载
                }
                else
                {
                    //加载图片
                }
    


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月14日 1:23
    版主
  • 如果我不是从磁盘加载图片,是从数据库中读取图片,用Dispose会找不到实例呢》?


            private void VreadImage()
            {
                SqlConnection cn = LinkDB.LinkDBSqlconnection(cnstr);
                if (cn.State == ConnectionState.Closed) cn.Open();
                string cmdstr = "select cardImage from CardImage where autoid=" +
                    recordNo;               
                SqlCommand cmd = new SqlCommand(cmdstr, cn);
                Byte[] b = (Byte[])cmd.ExecuteScalar(); 
                if (b.Length > 0)
                {
                    MemoryStream ms = new MemoryStream(b, true);               
                    ms.Write(b, 0, b.Length);
                 
                    //pictureBox1.Image.Dispose();//有了这句会出错的???              
                    this.pictureBox1.Image = Image.FromStream(ms);               
                    ms.Dispose();
                }
                cn.Dispose();
            }

    dear

    你得在释放前检查是否为空,这跟数据库一点关系都没有.

    http://www.dotblogs.com.tw/yc421206/archive/2009/11/01/11370.aspx

     


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2011年10月14日 8:23
  • 还是占用很大的内存,只是比以前要小一点,但释放的不是很及时,这是NET的通病

    谢谢你的帮助!!

    2011年10月14日 13:59
  • .Net 中的GC是不定时触发的和隐式执行。只要内存足够使用,他就不会被触发。

    但是我们可以显示的指定GC执行,前面有提到的GC.Collect()。

     


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月17日 2:04
    版主