VB.NET从SQL Server读取图片报System.OutOfMemoryException内存溢出错误
问题原因
你遇到的内存溢出错误核心原因是GDI+图像资源未正确释放,.NET的垃圾回收器不会自动回收Image类型占用的非托管资源,每次给按钮BackgroundImage赋新值时,旧的Image对象一直残留在内存中,累积之后就会触发内存不足报错。
另外你当前的逐ID查询数据库的逻辑会产生不必要的连接开销,也会间接增加内存占用。
解决方案
1. 赋值前释放旧图像资源
每次给按钮设置背景图之前,先手动释放已有的BackgroundImage资源。
2. 修复图像加载逻辑
Image.FromStream 要求流在图像使用期间保持打开,你可以通过克隆图像对象规避这个问题,避免后续访问图像时出现未知错误。
3. (可选优化)合并查询逻辑
将多次单ID查询合并为一次批量查询,减少数据库连接开销。
修正后参考代码
首先封装通用的按钮背景设置方法:
Private Sub SetButtonBackground(btn As Button, imgBytes As Byte()) ' 释放旧资源 If btn.BackgroundImage IsNot Nothing Then btn.BackgroundImage.Dispose() btn.BackgroundImage = Nothing End If If imgBytes Is Nothing OrElse imgBytes.Length = 0 Then Return End If Using ms As New MemoryStream(imgBytes) ' 克隆图像解除对MemoryStream的依赖 btn.BackgroundImage = CType(Image.FromStream(ms).Clone(), Image) End Using End Sub
调整查询和绑定逻辑:
Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click Dim dt As DataTable Try ' 一次性查询ID为1和2的两条记录 dt = GetInventoryDataByIdList(New Integer() {1, 2}) Catch ex As Exception MessageBox.Show(ex.Message) Exit Sub End Try ' 绑定按钮1 Dim dr1 = dt.Select("ID=1").FirstOrDefault() If dr1 IsNot Nothing Then Boton1.Text = dr1("Articulo").ToString() Boton1.Enabled = CBool(dr1("ONOFF")) Dim imgBytes = If(IsDBNull(dr1("Imagen")), Nothing, DirectCast(dr1("Imagen"), Byte())) SetButtonBackground(Boton1, imgBytes) Else MessageBox.Show("ID=1无对应记录") End If ' 绑定按钮2 Dim dr2 = dt.Select("ID=2").FirstOrDefault() If dr2 IsNot Nothing Then Boton2.Text = dr2("Articulo").ToString() Boton2.Enabled = CBool(dr2("ONOFF")) Dim imgBytes = If(IsDBNull(dr2("Imagen")), Nothing, DirectCast(dr2("Imagen"), Byte())) SetButtonBackground(Boton2, imgBytes) Else MessageBox.Show("ID=2无对应记录") End If End Sub ' 批量查询方法 Private Function GetInventoryDataByIdList(idList As Integer()) As DataTable Dim dt As New DataTable() ' 生成参数占位符 Dim paramNames = Enumerable.Range(0, idList.Length).Select(Function(i) "@ID" & i).ToArray() Dim sql As String = $"SELECT ID, Imagen, Articulo, ONOFF FROM Inventario WHERE ID IN ({String.Join(",", paramNames)})" Using con As New SqlConnection("你的连接字符串"), cmd As New SqlCommand(sql, con) ' 添加参数 For i = 0 To idList.Length - 1 cmd.Parameters.Add("@ID" & i, SqlDbType.Int).Value = idList(i) Next con.Open() Using myreader As SqlDataReader = cmd.ExecuteReader() dt.Load(myreader) End Using End Using Return dt End Function
注意事项
如果数据库中存储的图片二进制数据本身损坏,Image.FromStream也可能抛出内存溢出错误,你可以先导出数据库中的图片文件验证是否可以正常打开。
内容的提问来源于stack exchange,提问作者howdy
相关产品推荐
相关产品推荐

