#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 или использование хорошо структурированного потока ошибок может избежать проблем такого типа.
С наилучшими пожеланиями, Пауло Буэно.