You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 19:15:05