积极答复者
为什么会内存溢出呢?

问题
-
//我用的是Sql2008 中的FileStream特性取出大文件,约500M //我的代码如下: SqlConnection conn = new SqlConnection("server=my\\data2008;user id=zjh;password=321321;database=test"); conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select FSData from FileStreamTable where fs_id='"+textBox1.Text.Trim()+"'"; cmd.CommandTimeout = 999999; SqlDataReader dr = cmd.ExecuteReader(); SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "音乐文件(*.*)|*.*"; if (dialog.ShowDialog() == DialogResult.OK) { dr.Read(); System.Data.SqlTypes.SqlBinary result = dr.GetSqlBinary(0); FileStream fs = new FileStream(dialog.FileName, FileMode.Create); fs.Write(result.Value, 0, result.Length);//这里会内存溢出??? dr.Close(); fs.Flush(); fs.Dispose(); }
答案
-
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Data.SqlClient; using WindowsApplication1.TestDataSetTableAdapters; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { if (this.openFileDialog1.ShowDialog() == DialogResult.OK) { try { Stream fs = this.openFileDialog1.OpenFile(); FileStreamTableTableAdapter adpter = new FileStreamTableTableAdapter(); byte[] fileData = new byte[fs.Length]; fs.Read(fileData, 0, (int)fileData.Length); adpter.Insert(fileData); MessageBox.Show("Succeed!"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } private void button2_Click(object sender, EventArgs e) { if (this.saveFileDialog1.ShowDialog() == DialogResult.OK) { FileStreamTableTableAdapter adpter = new FileStreamTableTableAdapter(); byte[] fileData = (byte[])adpter.GetData().Rows[0][0]; FileStream fs = new FileStream(this.saveFileDialog1.FileName, FileMode.Create); fs.Write(fileData, 0, fileData.Length); fs.Flush(); fs.Dispose(); } } } }
你好 我做了上面的测试:
最开始我尝试插入一个600MB的文件,结果本地的SQL server服务器和这个程序都占用了大量的内存 大概都是600MB以上
而且一直插入不进去 因为数据库超时虽然我已经设置不超时
后来我插入一个265MB大小的,第一次是出现和你一样的情况,内存溢出
我restart了数据库服务,就成功上传。
再次restar 执行和你一样的操作即查询数据写入到本地磁盘文件
这个时候 数据库占用300多MB内存 这个程序占用500多MB内存,不过最终还是成功了
但是我相信如果我这里也是查询出来600多MB 那么内存占用估计超过1GB 就很有可能出现内存溢出的情况了。
所以对于你这种情况,非必须的情况下,我的建议是数据库中不要保存这么大的文件,而是保存文件路径,以ftp等方式上传文件至数据库。
另外你还可以采用分批次分段读取 然后写入到磁盘中,http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader.getbytes%28v=VS.80%29.aspx
Raymond Tang (Microsoft C# MVP)
Denn Ich Gehoer nur mir
.NET交流群71840452
微软中文论坛同城社区成都QQ群:74268428
My Chinese Blog
Chengdu,Sichuan Province,China- 已建议为答案 WayneYe 2010年11月15日 3:09
- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
-
Hi Raymond
我看了您提供的论坛地址,有一个问题:FileStreamTableTableAdapter是个什么对象?我google没有结果,是您自己写的Class?能否share一下相关信息?
IMHO,我个人认为楼主的问题可能与数据库没有关系,因为是OutofMemoryException!
我个人认为是因为一次性读取大文件到Streeam里(也就是内存当中),导致CLR无法继续开辟内存空间以存储文件流,而抛出OutOfMemoryExceptionRefer:http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx
而解决方案基本上至少有2种:1。 分块读取/写入文件到流(内存),分块写入,下面是分块读/写的示例代码
while (reader.Peek() >= 0) { char[] c = new char[50 * 1024 * 1024]; reader.Read(c, 0, c.Length); using (StreamWriter writer = File.Create("C:\\somefile.dat")) { writer.Write(c, 0, c.Length); write.Flush(true); writer.Close(); } }
2。加大内存(想想一下如果服务器有16G内存,则正常情况下读取500M的文件不会抛出OutOfMemoryException)。
Please feel free to let me know if you have any further issues, thanks!
Happy Coding:)Wayne Ye - Senior Software Development EngineerEmail: wayneyedotcom@gmail.com
- 已标记为答案 zjh111 2010年12月3日 17:17
-
dear
使用分批读/写挡的方法试试,主要是用二进位处理方式,读入缓冲区。
可用
BufferedStream + FileStream
BufferedStream + MemoryStream
以下几个例子,看看能解决你的问题
http://www.dotblogs.com.tw/yc421206/archive/2009/11/01/11370.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/27/11312.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/28/11324.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/30/11357.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/29/11349.aspx
秘訣無它,唯勤而已- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
-
Hi Raymond
我看了您提供的论坛地址,有一个问题:FileStreamTableTableAdapter 是个什么对象?我google没有结果,是您自己写的Class?能否share一下相关信息?
IMHO,我个人认为楼主的问题可能与数据库没有关系 ,因为是OutofMemoryException !
我个人认为是因为一次性读取大文件到Streeam里(也就是内存当中),导致CLR无法继续开辟内存空间以存储文件流,而抛出OutOfMemoryExceptionRefer:http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx
而解决方案基本上至少有2种:1。 分块读取/写入文件到流(内存),分块写入,下面是分块读/写的示例代码
while (reader.Peek() >= 0) { char [] c = new char [50 * 1024 * 1024]; reader.Read(c, 0, c.Length); using (StreamWriter writer = File.Create("C:\\somefile.dat" )) { writer.Write(c, 0, c.Length); write.Flush(true ); writer.Close(); } }
2。加大内存(想想一下如果服务器有16G内存,则正常情况下读取500M的文件不会抛出OutOfMemoryException)。
Please feel free to let me know if you have any further issues, thanks!
Happy Coding:)Wayne Ye - Senior Software Development EngineerEmail: wayneyedotcom@gmail.com
Hi Wayne,FileStreamTableTableAdapter是我建立的强类型的DataSet VS自动生成的一个类,它包含了Adapter、Connection等,这样可以方便的直接使用相关的方法
IMHO,我个人认为楼主的问题可能与数据库没有关系 ,因为是OutofMemoryException !
你这里的说法是正确的,这个问题跟数据库没多大关系,我只是在结尾建议楼主不要将这么大的文件存入数据库,存入磁盘然后保存路径可能会更好。
分批次分段的读取应该是可以解决这个问题的,使用SqlDataReader读取 http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader.getbytes%28v=VS.80%29.aspx
Raymond Tang (Microsoft C# MVP)
Denn Ich Gehoer nur mir
.NET交流群71840452
微软中文论坛同城社区成都QQ群:74268428
My Chinese Blog
Chengdu,Sichuan Province,China- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
全部回复
-
//我用的是Sql2008 中的FileStream特性取出大文件,约500M //我的代码如下: SqlConnection conn = new SqlConnection("server=my\\data2008;user id=zjh;password=321321;database=test"); conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select FSData from FileStreamTable where fs_id='"+textBox1.Text.Trim()+"'"; cmd.CommandTimeout = 999999; SqlDataReader dr = cmd.ExecuteReader(); SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "音乐文件(*.*)|*.*"; if (dialog.ShowDialog() == DialogResult.OK) { dr.Read(); System.Data.SqlTypes.SqlBinary result = dr.GetSqlBinary(0); FileStream fs = new FileStream(dialog.FileName, FileMode.Create); fs.Write(result.Value, 0, result.Length);//这里会内存溢出??? dr.Close(); fs.Flush(); fs.Dispose(); }
- 已合并 Raymond TangModerator 2010年11月12日 11:49 duplicate
-
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Data.SqlClient; using WindowsApplication1.TestDataSetTableAdapters; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { if (this.openFileDialog1.ShowDialog() == DialogResult.OK) { try { Stream fs = this.openFileDialog1.OpenFile(); FileStreamTableTableAdapter adpter = new FileStreamTableTableAdapter(); byte[] fileData = new byte[fs.Length]; fs.Read(fileData, 0, (int)fileData.Length); adpter.Insert(fileData); MessageBox.Show("Succeed!"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } private void button2_Click(object sender, EventArgs e) { if (this.saveFileDialog1.ShowDialog() == DialogResult.OK) { FileStreamTableTableAdapter adpter = new FileStreamTableTableAdapter(); byte[] fileData = (byte[])adpter.GetData().Rows[0][0]; FileStream fs = new FileStream(this.saveFileDialog1.FileName, FileMode.Create); fs.Write(fileData, 0, fileData.Length); fs.Flush(); fs.Dispose(); } } } }
你好 我做了上面的测试:
最开始我尝试插入一个600MB的文件,结果本地的SQL server服务器和这个程序都占用了大量的内存 大概都是600MB以上
而且一直插入不进去 因为数据库超时虽然我已经设置不超时
后来我插入一个265MB大小的,第一次是出现和你一样的情况,内存溢出
我restart了数据库服务,就成功上传。
再次restar 执行和你一样的操作即查询数据写入到本地磁盘文件
这个时候 数据库占用300多MB内存 这个程序占用500多MB内存,不过最终还是成功了
但是我相信如果我这里也是查询出来600多MB 那么内存占用估计超过1GB 就很有可能出现内存溢出的情况了。
所以对于你这种情况,非必须的情况下,我的建议是数据库中不要保存这么大的文件,而是保存文件路径,以ftp等方式上传文件至数据库。
另外你还可以采用分批次分段读取 然后写入到磁盘中,http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader.getbytes%28v=VS.80%29.aspx
Raymond Tang (Microsoft C# MVP)
Denn Ich Gehoer nur mir
.NET交流群71840452
微软中文论坛同城社区成都QQ群:74268428
My Chinese Blog
Chengdu,Sichuan Province,China- 已建议为答案 WayneYe 2010年11月15日 3:09
- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
-
你好 请参考我给你的回复
http://social.msdn.microsoft.com/Forums/zh-CN/2212/thread/40a09603-57f2-407c-a49d-a0cdbd4ee79f
Raymond Tang (Microsoft C# MVP)
Denn Ich Gehoer nur mir
.NET交流群71840452
微软中文论坛同城社区成都QQ群:74268428
My Chinese Blog
Chengdu,Sichuan Province,China -
Hi Raymond
我看了您提供的论坛地址,有一个问题:FileStreamTableTableAdapter是个什么对象?我google没有结果,是您自己写的Class?能否share一下相关信息?
IMHO,我个人认为楼主的问题可能与数据库没有关系,因为是OutofMemoryException!
我个人认为是因为一次性读取大文件到Streeam里(也就是内存当中),导致CLR无法继续开辟内存空间以存储文件流,而抛出OutOfMemoryExceptionRefer:http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx
而解决方案基本上至少有2种:1。 分块读取/写入文件到流(内存),分块写入,下面是分块读/写的示例代码
while (reader.Peek() >= 0) { char[] c = new char[50 * 1024 * 1024]; reader.Read(c, 0, c.Length); using (StreamWriter writer = File.Create("C:\\somefile.dat")) { writer.Write(c, 0, c.Length); write.Flush(true); writer.Close(); } }
2。加大内存(想想一下如果服务器有16G内存,则正常情况下读取500M的文件不会抛出OutOfMemoryException)。
Please feel free to let me know if you have any further issues, thanks!
Happy Coding:)Wayne Ye - Senior Software Development EngineerEmail: wayneyedotcom@gmail.com
- 已标记为答案 zjh111 2010年12月3日 17:17
-
dear
使用分批读/写挡的方法试试,主要是用二进位处理方式,读入缓冲区。
可用
BufferedStream + FileStream
BufferedStream + MemoryStream
以下几个例子,看看能解决你的问题
http://www.dotblogs.com.tw/yc421206/archive/2009/11/01/11370.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/27/11312.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/28/11324.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/30/11357.aspx
http://www.dotblogs.com.tw/yc421206/archive/2009/10/29/11349.aspx
秘訣無它,唯勤而已- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
-
Hi Raymond
我看了您提供的论坛地址,有一个问题:FileStreamTableTableAdapter 是个什么对象?我google没有结果,是您自己写的Class?能否share一下相关信息?
IMHO,我个人认为楼主的问题可能与数据库没有关系 ,因为是OutofMemoryException !
我个人认为是因为一次性读取大文件到Streeam里(也就是内存当中),导致CLR无法继续开辟内存空间以存储文件流,而抛出OutOfMemoryExceptionRefer:http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx
而解决方案基本上至少有2种:1。 分块读取/写入文件到流(内存),分块写入,下面是分块读/写的示例代码
while (reader.Peek() >= 0) { char [] c = new char [50 * 1024 * 1024]; reader.Read(c, 0, c.Length); using (StreamWriter writer = File.Create("C:\\somefile.dat" )) { writer.Write(c, 0, c.Length); write.Flush(true ); writer.Close(); } }
2。加大内存(想想一下如果服务器有16G内存,则正常情况下读取500M的文件不会抛出OutOfMemoryException)。
Please feel free to let me know if you have any further issues, thanks!
Happy Coding:)Wayne Ye - Senior Software Development EngineerEmail: wayneyedotcom@gmail.com
Hi Wayne,FileStreamTableTableAdapter是我建立的强类型的DataSet VS自动生成的一个类,它包含了Adapter、Connection等,这样可以方便的直接使用相关的方法
IMHO,我个人认为楼主的问题可能与数据库没有关系 ,因为是OutofMemoryException !
你这里的说法是正确的,这个问题跟数据库没多大关系,我只是在结尾建议楼主不要将这么大的文件存入数据库,存入磁盘然后保存路径可能会更好。
分批次分段的读取应该是可以解决这个问题的,使用SqlDataReader读取 http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader.getbytes%28v=VS.80%29.aspx
Raymond Tang (Microsoft C# MVP)
Denn Ich Gehoer nur mir
.NET交流群71840452
微软中文论坛同城社区成都QQ群:74268428
My Chinese Blog
Chengdu,Sichuan Province,China- 已标记为答案 BoberSongModerator 2010年11月17日 5:16
-
Hi Raymond
OK,没有问题:)
Happy Coding:)Wayne Ye - Senior Software Development EngineerEmail: wayneyedotcom@gmail.com