“System.OutOfMemoryException: 'Out of memory.'” 从 SQL Server 读取图像时

Posted

技术标签:

【中文标题】“System.OutOfMemoryException: \'Out of memory.\'” 从 SQL Server 读取图像时【英文标题】:"System.OutOfMemoryException: 'Out of memory.'" when reading image from SQL Server“System.OutOfMemoryException: 'Out of memory.'” 从 SQL Server 读取图像时 【发布时间】:2022-01-12 01:06:38 【问题描述】:

我为我的 VB.NET 表单中的每个按钮分配了图像,这些图像来自 SQL Server。数据类型为varbinary(MAX)

这是我的代码:

Using con As New SqlConnection("con string")
    Dim sql As String = "SELECT * FROM Inventory WHERE ID=@ID"
    Using cmd As New SqlCommand(sql, con)
        cmd.Parameters.Add("@ID", SqlDbType.VarChar).Value = 3
        con.Open()
        Using myreader As SqlDataReader = cmd.ExecuteReader()
            If myreader.Read() AndAlso Not DBNull.Value.Equals(myreader("Image")) Then
                Boton3.Text = myreader("Item")
                Boton3.Enabled = myreader("ONOFF")
                Dim ImgSql() As Byte = DirectCast(myreader("Image"), Byte())
                Using ms As New MemoryStream(ImgSql)
                    Boton3.BackgroundImage = Image.FromStream(ms)
                    con.Close()
                End Using
            Else
                Boton3.Text = myreader("Item")
                Boton3.BackgroundImage = Nothing
                Boton3.Enabled = myreader("ONOFF")
            End If
        End Using
    End Using
End Using

平台是 64 位的。我认为这可能与处理不当有关,但我不确定,因为我是编码新手。

编辑显示新代码以及我如何检索多条记录:

Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click
        Dim dt As DataTable
        Try
            dt = GetInventoryDataByID(1)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Exit Sub
        End Try
        If dt.Rows.Count > 0 Then
            Boton1.Text = dt.Rows(0)("Articulo").ToString
            Boton1.Enabled = CBool(dt.Rows(0)("ONOFF"))
            If Not DBNull.Value.Equals(dt.Rows(0)("Imagen")) Then
                Dim ImgSql() As Byte = DirectCast(dt.Rows(0)("Imagen"), Byte())
                Using ms As New MemoryStream(ImgSql)
                    Boton1.BackgroundImage = Image.FromStream(ms)
                End Using
            Else
                Boton1.BackgroundImage = Nothing
            End If
        Else
            MessageBox.Show("No records returned")
        End If
        Dim dt2 As DataTable
        Try
            dt2 = GetInventoryDataByID(2)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Exit Sub
        End Try
        If dt2.Rows.Count > 0 Then
            Boton2.Text = dt2.Rows(0)("Articulo").ToString
            Boton2.Enabled = CBool(dt2.Rows(0)("ONOFF"))
            If Not DBNull.Value.Equals(dt2.Rows(0)("Imagen")) Then
                Dim ImgSql() As Byte = DirectCast(dt2.Rows(0)("Imagen"), Byte())
                Using ms As New MemoryStream(ImgSql)
                    Boton2.BackgroundImage = Image.FromStream(ms)
                End Using
            Else
                Boton2.BackgroundImage = Nothing
            End If
        Else
            MessageBox.Show("No records returned")
        End If
    End Sub
    Private Function GetInventoryDataByID(id As Integer) As DataTable
        Dim dt As New DataTable
        Dim sql As String = "SELECT Imagen, Articulo, ONOFF FROM Inventario WHERE ID=@ID"
        Using con As New SqlConnection("CON STRING"),
            cmd As New SqlCommand(sql, con)
            cmd.Parameters.Add("@ID", SqlDbType.Int).Value = id
            con.Open()
            Using myreader As SqlDataReader = cmd.ExecuteReader()
                dt.Load(myreader)
            End Using
        End Using
        Return dt
    End Function
End Class

【问题讨论】:

仅供参考interesting article 该错误消息也可能意味着数据有问题。如果将数据保存到磁盘,是否可以使用 IrfanView 之类的图像将其打开? 代码错误在哪一行? @AndrewMorton 我可以在另一个名为 photo paint 的软件上打开图像。 @howdy 哦,不!我们将如何发现问题?那么,是什么让您认为您在问题中显示的代码是问题所在?您是否注释掉了检索图像的代码? (请记住,由于维护,我们目前无法看到监控您显示器的监控摄像头。) 【参考方案1】:

您不希望在更新用户界面时保持连接打开。将用户界面代码与数据库代码分开。

如果您在外部 Using 块的第一行末尾放置一个逗号,则命令和连接都包含在同一个块中。节省了一点缩进。

您将整数传递给@ID 参数,但您已将SqlDbType 设置为VarChar。看起来有问题。我将SqlDbType 更改为Int

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim dt As DataTable
    Try
        dt = GetInventoryDataByID(3)
    Catch ex As Exception
        MessageBox.Show(ex.Message)
        Exit Sub
    End Try
    If dt.Rows.Count > 0 Then
        Boton3.Text = dt.Rows(0)("Item").ToString
        Boton3.Enabled = CBool(dt.Rows(0)("ONOFF"))
        If Not DBNull.Value.Equals(dt.Rows(0)("Image")) Then
            Dim ImgSql() As Byte = DirectCast(dt.Rows(0)("Image"), Byte())
            Using ms As New MemoryStream(ImgSql)
                Boton3.BackgroundImage = Image.FromStream(ms)
            End Using
        Else
            Boton3.BackgroundImage = Nothing
        End If
    Else
        MessageBox.Show("No records returned")
    End If
End Sub

Private Function GetInventoryDataByID(id As Integer) As DataTable
    Dim dt As New DataTable
    Dim sql As String = "SELECT * FROM Inventory WHERE ID=@ID"
    Using con As New SqlConnection("con string"),
            cmd As New SqlCommand(sql, con)
        cmd.Parameters.Add("@ID", SqlDbType.Int).Value = id
        con.Open()
        Using myreader As SqlDataReader = cmd.ExecuteReader()
            dt.Load(myreader)
        End Using
    End Using
    Return dt
End Function

编辑在图像上添加 Dispose

    If Not DBNull.Value.Equals(dt.Rows(0)("Image")) Then
        Dim ImgSql() As Byte = DirectCast(dt.Rows(0)("Image"), Byte())
        Using ms As New MemoryStream(ImgSql)
            If Boton3.BackgroundImage IsNot Nothing Then
                Boton3.BackgroundImage.Dispose()
            End If
            Boton3.BackgroundImage = Image.FromStream(ms)
        End Using
    Else
        If Boton3.BackgroundImage IsNot Nothing Then
            Boton3.BackgroundImage.Dispose()
        End If
    End If

【讨论】:

我在 mybase.load 事件中尝试了您的解决方案。我仍然得到同样的错误。仅当多个按钮具有图像(总共 15 个按钮)时才会发生该错误。一旦我加载表单,错误也会发生。它不会显示出错的代码行,但会显示Your app has entered a break state, but there is no code to show because all threads were executing external code (typically system or framework code). 您的代码显示返回一条记录。显示要检索多条记录的代码。出于测试目的,将代码移出Form_Load 并在表单上粘贴一个按钮以执行操作。 感谢玛丽的回复。我编辑了我的问题以显示我如何检索多条记录。我还在Button_Click 上测试了操作,出现了同样的错误。 我在图像上添加了调用 Dispose。这可能有助于解决内存问题。 我通过不使用按钮解决了这个问题。相反,我使用图片框作为按钮,这解决了这个问题。我猜问题是按钮不允许像图片框那样多的内存。我仍然会接受您的回答,因为我从您的代码中学到了很多东西。谢谢玛丽!【参考方案2】:

我通过不使用按钮解决了这个问题。相反,我使用图片框作为按钮,这解决了这个问题。我猜这个问题是按钮不允许像图片框一样多的内存。

【讨论】:

以上是关于“System.OutOfMemoryException: 'Out of memory.'” 从 SQL Server 读取图像时的主要内容,如果未能解决你的问题,请参考以下文章