首页 新闻 会员 周边

Bitmap 引起内存不足问题解决。路过的朋友帮忙看下谢谢

0
悬赏园豆:20 [已解决问题] 解决于 2018-04-04 20:18

需求:旧系统数据库 图片存的是进制。数据有13w条(历史原因)。需要把图片进制转换对应的图片保存到本地  新系统保存图片地址。。现在写一个小程序需要转换旧系统图片数据  winfrom

复制代码
                    while (_isWhile)
                    {
                        sql= txtSql.Text.Replace(row, _nextRow).Replace(pagesize, txtRow.Text);
                        Logging.Instance.WriteEnqueue(null, sql);
                        var dt = GetImgData(sql);

                        if (dt == null)
                        {
                            //没有数据自动终止循环
                            _isWhile = false;
                            lblMsg.Text = "执行完成";
                            Logging.Instance.WriteEnqueue(null, lblMsg.Text);
                            return ;
                        }

                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
//文件名
var imgName = dt.Rows[i][fileName];
//图片进制
var stream = dt.Rows[i][fileStream]; if (string.IsNullOrEmpty(stream.ToString())) { Logging.Instance.WriteEnqueue(null, imgName + "对应列数据为空"); continue; } byte[] imagebytes = (byte[])stream; var filename = path + "\\" + imgName + ".jpg"; //问题出现在这里 如何解决呢? using (MemoryStream ms = new MemoryStream(imagebytes)) { Bitmap bmpt = new Bitmap(ms); bmpt.Save(filename, ImageFormat.Jpeg); } GC.Collect(); Thread.Sleep(20); _indexSuccess++; } _whileCout++; _nextRow = (_whileCout * int.Parse(txtRow.Text)).ToString(); if (!string.IsNullOrEmpty(txtRowStrar.Text)) { _nextRow = (_whileCout * int.Parse(txtRow.Text)+int.Parse(txtRowStrar.Text)).ToString(); } lblMsg.Text = "当前循环次数"+ _whileCout; GC.Collect(); Thread.Sleep(1000); }
复制代码

目前是分批读取数据 。但是这里

Bitmap 这块这样写我知道也有问题 不停的创建对象。 内存溢出。如何解决呢?

解决code:
            _indexSuccess = 0;
            BtnImg.Enabled = false;
            if (BtnImgVerification()) return;
            Logging.Instance.CreateFile(txtPath.Text);

            lblMsg.Text = "程序执行中.......";
            Task.Factory.StartNew(() =>
            {
                ExceptionsHelp.Instance.ExecuteVoidFunc(() =>
                {
                    var dr = DbHelperSql.ExecuteReader(txtSql.Text);
                    var ms = new MemoryStream();
                    while (dr.Read())
                    {
                        var imgName = dr[txtFileName.Text];
                        var stream = dr[txtFileStream.Text];

                        if (string.IsNullOrEmpty(stream.ToString()))
                        {
                            Logging.Instance.WriteEnqueue(null, imgName + "对应列数据为空");
                            continue;
                        }
                        byte[] imagebytes = (byte[])stream;
                        var filename = txtPath.Text + "\\" + imgName + ".jpg";
                        ms.Write(imagebytes, 0, imagebytes.Length);
                        using (FileStream fsWrite = new FileStream(filename, FileMode.Append))
                        {
                            fsWrite.Write(imagebytes, 0, imagebytes.Length);
                        };
                        ms.Position = 0;
                        _indexSuccess++;
                    }
                    ms.Dispose();
                    ms.Close();
                    dr.Close();
                    GC.Collect();
                    Logging.Instance.WriteEnqueue(null, _indexSuccess.ToString());
                    MessageBox.Show(_indexSuccess.ToString());

                }, "BtnImg_Click", () =>
                {
                    Method(BtnImg, x => x.Enabled = true);
                });
            });

 

 
问题补充:

解决了 之前是分段加载 用的dataset 错误提示是System.Drawing 提示内存不足

dudu 建议改成 SqlDataReader居然成功了。

奇怪的是dataset内存引起的为什么提示 System.Drawing 呢。目前解决这个问题了

图片转换导入成功44G

s_p的主页 s_p | 初学一级 | 园豆:138
提问于:2018-04-04 18:01
< >
分享
最佳答案
0

Bitmap 也要放在 using 中

using (MemoryStream ms = new MemoryStream(imagebytes))
{
    using(Bitmap bmpt = new Bitmap(ms))
    {
        bmpt.Save(filename, ImageFormat.Jpeg);
    }
}
收获园豆:11
dudu | 高人七级 |园豆:31007 | 2018-04-04 18:11

试了 不行的

s_p | 园豆:138 (初学一级) | 2018-04-04 18:28

@s_p: 电脑多少内存?

dudu | 园豆:31007 (高人七级) | 2018-04-04 18:38

@s_p: 另外建议去掉GC.Collect();

dudu | 园豆:31007 (高人七级) | 2018-04-04 18:40

@dudu: 16G  去掉 了GC.Collect()

s_p | 园豆:138 (初学一级) | 2018-04-04 18:52

@dudu: 循环次数多了 有问题 。其实想洗 循环13w次(分段) 这个Bitmap对象new那么多次  释放好像没起作用。

s_p | 园豆:138 (初学一级) | 2018-04-04 18:53

@s_p: 什么时候释放是由GC决定的

dudu | 园豆:31007 (高人七级) | 2018-04-04 19:09

@s_p: 为什么要Thread.Sleep(20);?建议去掉

dudu | 园豆:31007 (高人七级) | 2018-04-04 19:10

@dudu: 去掉了 不行 基本上是循环到1w次 (读取了2次数据库 就挂了)

s_p | 园豆:138 (初学一级) | 2018-04-04 19:16

@s_p: DataTable 也是耗内存大户,建议使用 DataReader

dudu | 园豆:31007 (高人七级) | 2018-04-04 19:23

@dudu: 解决了 果然是dataset的问题引起的.但是我是分段读取的 读取了几万后 提示内存不足 不懂。

s_p | 园豆:138 (初学一级) | 2018-04-04 20:01

@dudu: 谢谢。

s_p | 园豆:138 (初学一级) | 2018-04-04 20:10
其他回答(3)
0

是datatable的问题.

你把循环放外面.给表加一个是否已保存字段.

while(select count(1) from 表 where 已保存=0)

{

select top 1 * from 表 where 已保存=0

保存到文件中

update 已保存=1 where id=上面取到的id

}

收获园豆:2
吴瑞祥 | 园豆:29449 (高人七级) | 2018-04-04 18:08

和这个没有关系。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 18:28

不是sql的问题。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 18:31

x谢谢了 问题解决了 朋友

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 20:19
0

你的数据有13万条,这样就要循环13万次,然后你Bitmap bmpt = new Bitmap(ms); 创建了13万次。有13万个对象占用了内存。我的建议把bmpt定义在for循环外部.循环内部重用对象。在编码的时候很多时候遇到这种情况,应该在循环外部定义对象。

Bitmap bmpt = new Bitmap();

for(xxxx)

{

   bmpt.xxx = ms

}

收获园豆:2
Shendu.CC | 园豆:2138 (老鸟四级) | 2018-04-04 18:19

bmpt 如何把流填充进去的 这个是个问题。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 18:31

@s_p: 我思考了一下,在for循环中new 对象,是不会引起内存爆炸的,因为c#会自动回收。

你在每次save之后调用Dispose()函数看一看有没有效果

支持(0) 反对(0) Shendu.CC | 园豆:2138 (老鸟四级) | 2018-04-04 19:03

@Shendu.cc: dataset引起的 谢谢了朋友

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 20:19
0

如果不存在格式转换去掉Bitmap;

Using(DbConnection)

{

  while(DbReader().Read())

    {

        var buffer = 读取byte[]列;

        File.WriteAllBytes("文件名",buffer);

    }

}

以上方法比较最简洁和轻量。

多半作用域之类的出问题。

收获园豆:5
花飘水流兮 | 园豆:13560 (专家六级) | 2018-04-04 19:08

不行试了这个写法。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 19:17

@s_p: 你可以质疑我,但不要质疑微软,请检视自己的代码。

支持(0) 反对(0) 花飘水流兮 | 园豆:13560 (专家六级) | 2018-04-04 19:19

@花飘水流兮: 晕 你搜一下 网上很多提这个问题的。写了这个 自己测试了不是质疑。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 19:22

@花飘水流兮: 图片加起来都要20-30g 写着就出问题了。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 19:23

@花飘水流兮: 13w条数据。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 19:23

@花飘水流兮: 谢谢朋友。

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 20:19

 File.WriteAllBytes 批量的时候 会出现问题 朋友 文件大的时候。

https://www.cnblogs.com/Yanggulin/p/3769070.html

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2018-04-04 20:29

@s_p: 写过buffer都知道。既然都能村数据库,基本上可以断定没什么问题,OK?!。这就是为什么请求为什么分普通post和stream的原因。

支持(0) 反对(0) 花飘水流兮 | 园豆:13560 (专家六级) | 2018-04-06 02:18
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册