Тот же Winforms. Net двоичный файл использует намного больше памяти на одном P C и не освобождает его (G C не работает, может быть?) - PullRequest
1 голос
/ 17 февраля 2020

У меня проблема с приложением, которое сводит меня с ума, и я действительно не знаю, что еще я могу сделать, чтобы продолжить расследование.

У меня есть простое приложение Windows Forms (32-разрядное, VB. net, Framework 4.5.1), которое очень странно ведет себя на только одном P C, относительно распределения памяти. На всех других компьютерах, которые я пробовал, работает нормально! ДОЛЖНО быть что-то в этом конкретном P C, но я не могу понять, что это такое, если не считать переустановки всего по одному ...

на всех ПК , за исключением одного , использование памяти приложением в порядке и не превышает go 10-20 Мегабайт. Только на одном P C, что происходит Будучи моей собственной разработкой P C, память продолжает увеличиваться и никогда не освобождается, пока не достигнет предела 2 ГБ Windows и не выдаст исключение Out of Memory. Я скопировал одни и те же двоичные файлы на 6 разных ПК (четыре Win7, два Win10) и подтвердил, что приложение работает (и стабильно) на всех этих ПК. Только на моем P C, даже когда приложение запускается без инициализации передачи, кажется, что оно занимает как минимум на 20 мегабайт больше по сравнению с другими ПК. Так что, что бы это ни было, должно быть что-то на P C, которое вызывает это.

Приложение использует SqlDataReader с SqlBulkCopy для передачи нескольких гигабайт данных из одной базы данных в другую. Перевод осуществляется месяц за месяцем. Все объекты SqlDataReader, SqlBulkCopy, SqlConnection и SqlCommand располагаются после каждого месяца, поскольку я заключаю их в блок Using. Я даже звоню GC.Collect в конце каждой итерации.

Я даже использовал профилировщик памяти Visual Studio, чтобы попытаться выяснить, что происходит, но все, что он говорит, это то, что большая часть памяти запрашивается команда SqlBulkCopy.WriteToServer. Это не кажется особенно проницательным.

Теперь еще одно интересное замечание: если я использую метод Winapi EmptyWorkingSet после каждой итерации (не показано в коде ниже), память Кажется, освобождается. Так почему же Do tnet сборщик мусора не делает то же, что и ожидалось, и почему только на одном P C ???

Вот код. Некоторые части изменены, чтобы удалить конфиденциальные вещи. Это приложение VB. Net Winforms, использующее. Net Framework 4.5.1. Это построено на VS 2017, Windows 10.

Любые советы о том, как на земле исследовать это дальше, за исключением начала удаления Windows Обновлений и другого программного обеспечения по одному с этой конкретной рабочей станции, будет принята с благодарностью.

Большое спасибо!

Private Sub CopyData()

    ' Database connection strings for source and destination db
    Dim conn_string_source As String = "<CONFIDENTIAL DATA MASKED>",
        conn_string_destination As String = "<CONFIDENTIAL DATA MASKED>"

    ' For progress report.
    Dim rows_total As Long,
        rows_done As Long

    '
    ' Find total rows to transfer.
    ' For progress report.
    '
    Using _
        conn_src As New SqlConnection(conn_string_source),
        cmd As New SqlCommand("Select Count(*) From dbo.SOURCE_TABLE", conn_src)
        rows_total = CLng(cmd.ExecuteScalar())
        Console.WriteLine("{0:#,##0} total rows to transfer.", rows_total)
    End Using

    '
    ' Transfer rows for one year, one month at a time.
    ' Dispose connections, readers and bulkcopy class at end of each month.
    '
    For which_month = 1 To 12

        Using _
            conn_dest As New SqlConnection(conn_string_destination),
            conn_src As New SqlConnection(conn_string_source),
            bc = New SqlClient.SqlBulkCopy(conn_dest)

            '
            ' For progress report.
            ' Calculate rows for this month.
            '
            Dim rows_this_month As Long
            Using cmd = New SqlCommand("Select  Count(*) 
                                        From    dbo.SOURCE_TABLE 
                                        Where   posting_month = @mm", conn_src)
                cmd.Parameters.AddWithValue("@mm", which_month)
                rows_this_month = cmd.ExecuteScalar()
            End Using

            '
            ' Setup the Bulk Copy operation
            '
            bc.DestinationTableName = "dbo.TARGET_TABLE"
            bc.BulkCopyTimeout = 0      ' Never timeout
            bc.BatchSize = 3000         ' Rows per batch. This values seems efficient enough.
            bc.NotifyAfter = 250        ' Raise notification event after every this number of rows copies.
            ' Microsoft says for better memory usage, though tests indicate doesn't make difference.
            bc.EnableStreaming = True

            ' Notify us every few rows to know how much was finished.
            AddHandler bc.SqlRowsCopied,
                Sub(sndr, rr)
                    Console.WriteLine("      ...{0:#,##0} / {1:#,##0}", rr.RowsCopied, rows_this_month)
                End Sub

            '
            ' Perform the actual transfer.
            ' Feed a reader to the SqlBulkCopy operation.
            '
            Using cmd As New SqlCommand("Select * 
                                            From   dbo.SOURCE_TABLE 
                                            Where  posting_month = @mm", conn_src)

                cmd.Parameters.AddWithValue("@mm", which_month)
                Using rdr = cmd.ExecuteReader()
                    bc.WriteToServer(rdr)
                End Using

            End Using

            rows_done += rows_this_month
            Console.WriteLine("      GRAND TOTAL: {0:#,##0} / {1:#,##0}", rows_done, rows_total)

        End Using

        GC.Collect()

    Next

End Sub
...