vb.net таймер и исключение (попробуйте … поймать) и утечка памяти

#vb.net #error-handling #timer

#vb.net #обработка ошибок #таймер

Вопрос:

Сценарий: у меня есть сотни экземпляров приложений, запущенных на клиентских компьютерах, выполняющих определенную работу. Что-то вроде облачного приложения.

Цель: При возникновении ошибки в любом из них я хочу сообщить об ошибке в базу данных журнала ошибок и молча закрыть приложение, чтобы избежать раздражения пользователя.

Проблема: я перешел на VB.NET недавно и пока не знаю, какой наилучший подход к обработке кода с ошибкой. Эти экземпляры запускают процедуру по таймеру.

 Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
    MAINSUB()
End Sub

Friend Sub MAINSUB()
    frmSAN.timerLifeSignal.Enabled = False
    ...
    'do the job
    ...
    frmSAN.timerLifeSignal.Enabled = True
end sub
  

На первый взгляд, я вставил try / catch в каждую отдельную функцию, но это приводит к утечке памяти, поскольку, AFIK, созданный объект исключения не был размещен правильно.

Итак, есть ли способ заставить try / catch не допускать утечки памяти при этих обстоятельствах?

Спасибо,

ОБНОВЛЕНИЕ: В основном то, что я делал, это что-то вроде:

 Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
    MAINSUB()
End Sub

Friend Sub MAINSUB()
    Try
        frmSAN.timerLifeSignal.Enabled = False
        ...
        'do the job
        ...
        frmSAN.timerLifeSignal.Enabled = True

    Catch ex as Exception : gERRFUNC(" | MAIN | " amp; ex.Message) : End Try
end sub

friend sub dothejob
    try
        ...
        ' really do the job
        ...
    Catch ex as Exception : gERRFUNC(" | MAIN | " amp; ex.Message) : End Try
end sub
  

и так далее… и, наконец (возможно, здесь это моя ошибка), еще одна попытка / перехват, вложенная сюда:

 Public Sub gERRFUNC(Optional ByVal errorMSG As String = "")
    Try

        ' log message on database
        SQL = "INSERT INTO sanerrorlog VALUES (NULL, '" amp; currentMySQLTime() amp; "', '" amp; errorMSG amp; "');"
' function that open conn and execute the sql... working fine           
' NOTE THAT INSIDE THE DORS FUNCTION THERE'S ALSO A TRY/CATCH USING THE SAME EX OBJECT. 
        DORS(SQL) 
        ' clean up things
        SQL = "DELETE FROM sannie WHERE sid=" amp; gMyID
        DORS(SQL)
        For i = 0 To UBound(gCONN)
            If gCONN(i).State = ConnectionState.Open Then gCONN(i).Close()
        Next

        frmSAN.nfi.Visible = False
        gWWB = Nothing
        End
    Catch E As Exception:   End:        End Try
End Sub
  

Итак … если я сделаю это:

     Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
Try
        MAINSUB()
Catch ex as Exception : gERRFUNC(" | MAIN | " amp; ex.Message) : End Try
    End Sub
  

Означает, что все исключения внутри mainsub должны быть перехвачены?

Комментарии:

1. Try/catch это не утечка памяти. По-видимому, что-то еще в ‘do the job’ есть.

2. Я проверил это. Удалив все попытки / уловы, утечка памяти прекратилась. Я где-то читал (потерял ссылку, извините), что исключением является сам объект, что означает, что он должен быть утилизирован должным образом. Поскольку эти функции снижаются до 4 уровней, возможно, сборщик мусора vb не очищает эти объекты.

3. @Paulo Исключение не имеет метода Dispose и, следовательно, не может быть удалено. То, что вы, по-видимому, видите, это объекты исключения, которые еще не были собраны мусором (но будут в конечном итоге).

4. Хорошо, понял. Но мусор на самом деле вообще не собирался (что-то), поскольку приложение разогналось до 2 ГБ за несколько минут…

5. Вы понимаете, что ваш код ошибки уязвим для внедрения sql? Бьюсь об заклад, я мог бы манипулировать вашим сообщением об ошибке, чтобы с вашей базой данных происходили плохие вещи.

Ответ №1:

У вас есть другой способ..

Вы можете прикреплять события к домену приложения и основному потоку, в случае сбоя, для обнаружения ошибок.

Что-то вроде:

     AppDomain.CurrentDomain.UnhandledException  =
     CurrentDomain_UnhandledException;
    Application.ThreadException  =
      Application_ThreadException;
    Application.ApplicationExit  = Application_ApplicationExit;
  

имея это в виду, каждый раз, когда возникает исключение, в любом месте, где оно само по себе не имеет catch, оно будет проходить через любое из этих исключений…

Ответ №2:

Попытки / уловы сами по себе не вызывают утечек памяти. Однако не finalizing что-то после сбоя, которое вызывает catch can. Удалив ваши попытки / уловы, вы, по-видимому, предоставили что-то еще, что завершает, хотя и неофициально, объект, который вызывал утечку памяти.

Спросите себя, как директива в вашем коде может вызвать утечку памяти? Try и Catch не являются ссылками на объект и, следовательно, сами по себе не могут вызвать проблему с потреблением памяти — только по логическому пути кода, которым они управляют.

Комментарии:

1. Ну, мне это непонятно. Поскольку, если происходит сбой, он должен быть обнаружен одним из try / catch, и в этих случаях я (в процедуре catch) должен очистить вещи, сообщить и выйти из приложения. Также не получил открытую часть…

Ответ №3:

Просто для справки проблема с утечкой памяти возникает из-за вложенных циклов try / catch, которые (по моей ошибке) используют ту же переменную, что и объект exception. Для большей ясности возьмем следующий пример:

 Public Sub gERRFUNC(Optional ByVal errorMSG As String = "")
    Try
      // do something wrong here
    Catch E As Exception: gERRFUNC(ex.Message): End Try
End Sub

friend Sub gERRFUNC(msg as string)
    Try
        // call another external sub (wich eventually may also throw an execption)
        // take note that the var 'E' is also referenced here and everywhere
        // so as 'E' is set it enters on a Exception loop causing the 'memory leak' problem.
    Catch E as Exception: End: End Try
End Sub
  

Удаление вложенных try / catch или использование хорошо структурированного потока ошибок может избежать проблем такого типа.

С наилучшими пожеланиями, Пауло Буэно.