Archived Forum Post

Index of archived forum posts

Question:

Memory not freed after calling SendBytesAsync() and disposing of the Task and Socket objects

Nov 18 '16 at 17:23

I have a server application that sends files using Chilkat.Socket.SendBytesAsync(byte[]). The files are about 50MB in size on average.

When I call Task.Run() on the Task object returned from Chilkat.Socket.SendBytesAsync(byte[]), I see memory usage spike about 50MB as expected while the task is running. After the Task is running, I add the Task object to a ConcurrentDictionary collection along with the Socket and in another thread I check the progress of the running Tasks regularly. When each Task is complete, I dispose of the Task object and the Socket object that the Task used.

Unfortunately, memory usage never drops after disposing of the Task and the Socket. Every 50MB file I send yields another 50MB of memory usage. If I use the exact same code but call the synchronous method SendBytes, all memory is freed up after SendBytes is complete and I dispose of the Socket object, so it appears to have something to do with the Asynchronous call.

Following are some of my code snippets.

Here is where I am asynchronously sending the byte[]

Chilkat.Task t = tcpSocket.SendBytesAsync(bytesToSend);   
if (!t.Run())
    {
        LogError("failed to send file: " + tcpSocket.LastErrorText);
        return null;
    }
_remoteClients_DownloadsInProgress.TryAdd(tcpSocket, t); //add Task and Socket to a collection

Here, on another thread, is where I check the Task progress and dispose of it if it is completed:

            foreach(RemoteClient rc in _remoteClients_DownloadsInProgress.Keys)
        {
            _remoteClients_DownloadsInProgress.TryGetValue(tcpSocket, out taskout);

            if ((taskout.StatusInt == 7 && taskout.Finished && taskout.TaskSuccess) )
            {
                //close the socket
                LogDebugInfo("Task Complete!");
                try
                {
                    _remoteClients_DownloadsInProgress.TryRemove(tcpSocket, out taskout);
                    tcpSocket.Close(500);
                    taskout.Dispose();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                catch (Exception ex)
                {

                    LogException(ex);
                }

            }
        }

I am using version 9.5.0.58 of the ChilkatDotNet4.dll

Is there anything in particular I need to do to free up the memory used by the Chilkat dll when calling SendBytesAsync()?

Thanks


Accepted Answer

I found the cause of the problem. It's a problem specific to passing byte arrays to an Async method in .NET. This problem should be present in all async methods that have byte array arguments (but only for .NET). I should have it fixed for later today, and I'll post a v9.5.0.65 pre-release -- which should be stable because nothing much as occurred yet since v9.5.0.64 (see http://cknotes.com/v9-5-0-65-pre-release-notes/ )


Answer

Thanks.. I'll have a look..


Answer

Here's a new build that should fix it:

http://chilkatdownload.com/prerelease/chilkatdotnet4-9.5.0-win32.zip
http://chilkatdownload.com/prerelease/chilkatdotnet4-9.5.0-x64.zip

(I haven't tested it yet, but it should work..)

Also, the following Socket methods were added:

These are methods for sending/receiving directly from BinData and StringBuilder objects. See the online reference documentation at https://www.chilkatsoft.com/refdoc/csSocketRef.html

If the 50MB you're sending is data from a file, then you could instead instantiate a Chilkat.BinData object, load it with the file data, and then send it by calling SendBd. This is far better than calling SendBytes. The reason is that w/ SendBytes, the byte array must be marshaled from managed to unmanaged internally. This would cause a temporary spike in memory usage, and of course takes some time. If passing a BinData, then the data stays in unmanaged memory, and there's no memory usage spike, and no marshaling, so it should be faster.

But even if you still use SendBytes, the leak should be fixed.. (I'll verify by testing soon..)