BeginInvoke Memory Leak?

2019-07-16 08:35发布

问题:

I'm troubleshooting some weird behavior of a threaded application and have stumbled upon a few delegate functions that use the BeginInvoke(Deligate) call to start Async tasks. My research shows that using BeginInvoke without pairing to EndInvoke has the opportunity to cause Memory Leaks especially in the cases of Exceptions being thrown which I believe to be the case here.

The code I've been given calls a delegate and has a callback function that calls a new delegate itself. What I'm most curious with is how the callback is executed. Is it in any way necessary to issue a new delegate on the last line? That comment doesn't seem to make a lick of sense to me. Also, the callback's delegate call never issues an EndInvoke call causing leaks, is there a simpler method to cleaning this up then creating a callback method?

Another concern although less important is the name of the function as Synchronized. From what I see there is nothing forcing synchronization in the method call. Does VB.NET set up synchronization automatically or was the last developer just throwing words in to sound fancy?

The initial call:

mDelegateUpdate3.BeginInvoke(mCallbackUpdate3, mDelegateUpdate3)

The callback method:

Public Sub OnUpdateSchedule3Complete(ByVal ar As IAsyncResult)
        ' Clean up original thread
        Dim del As OPCConnectionWorkerDelegate
        del = CType(ar.AsyncState, OPCConnectionWorkerDelegate)
        del.EndInvoke(ar)

        'We are on the wrong thread so we need to switch back to the UI thread
        Dim ar1 As IAsyncResult
        ar1 = Me.BeginInvoke(New SynchronizedScheduleCompletedDelegate(AddressOf Me.SynchronizedScheduleCompleted))
End Sub

The SynchronizedScheduleCompleted Method:

Private Sub SynchronizedScheduleCompleted()
    mAttemptingUpdate = False
    mOPCConnectionWorker.clearInvolked()
    SetInProgress(False)
End Sub

回答1:

Correct; not calling EndInvoke() will create a memory leak.

If you just want to "fire-and-forget" an asynchronous operation and not handle its result, you should simply call ThreadPool.QueueUserWorkItem(), which has no potential for memory leaks.

If you do care about the result, you should use the Task class, which is much easier to use.

There is no longer any reason to call Delegate.BeginInvoke().

And, the word Synchronized in the names of the delegate and the method is meaningless.