locked
System.OutOfMemoryException RRS feed

  • Question

  • Hi,

    I have a thread which is running alway with a timer interval of 1sec. The thread functionality is to connect to a listen to the network and if any data, return back to the main form. I am using tcpListener calss to do that and it works fine. The problem is after running for few minutes my application is coming out with the error "An unhandled exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll". I'm in blur figuring the problem out.

    Why this is happening. Any problem with my Listemer class?? The below is the code which my thread is calling.

    Public Sub getNetworkRequest()
            tcpListener.Start()
            Console.WriteLine("Waiting for connection...")
            Try
                'Accept the pending client connection and return             'a TcpClient initialized for communication. 
                Dim tClient As TcpClient = tcpListener.AcceptTcpClient()
                Console.WriteLine("Connection accepted.")
                ' Get the stream
                Dim networkStream As NetworkStream = tClient.GetStream()
                ' Read the stream into a byte array
                Dim bytes(tClient.ReceiveBufferSize) As Byte
                networkStream.Read(bytes, 0, CInt(tClient.ReceiveBufferSize))
                ' Return the data received from the client to the console.
                Dim clientdata As String = Encoding.ASCII.GetString(bytes)
                'tcpListener.Stop()
                m_MainWindow.Invoke(m_NotifyMainWindow, clientdata)
    
            Catch ex As Exception
    
            End Try
        End Sub
    Friday, May 29, 2009 6:02 AM

Answers

  • The problem is most likely in the design of your application. Networking code in .NET can be non-intuitive, I know. Correct my understanding if it's wrong but you have a timer which every second calls the getNetworkRequest method in a different thread? If this is the case then while you may think you're only creating one thread you may be creating 1 every second. Follow me on this logic

    Your timer most likely runs on the UI thread every second. It kicks off new thread A and starts the getNetworkRequest method.

    tcpListener.AcceptTcpClient() method blocks until a request arrives; that is if there isn't one it'll wait forever. If it does wait forever then in a second the timer will kickoff another thread. If there is a connection great.

    tClient.ReceiveBufferSize by default has a size of 8KB so in making an array that large you are allocating another 8KB.
    the networkStream.Read method, not unlike the AcceptTcpClient method will block until either the underlying connection is closed or it fills its buffer. As written you code would only continue if it received a full 8KB of data (or the connection was closed). If this isn't the case it'll hang forever (and in a second another thread will kick off starting this process all over again).

    Dim clientData As String.Encoding.ASCII.GetString(bytes) doesn't tell GetString how many bytes were actually read and just assumes that the entire array is a string, so any extra data will be including in the string as null data (which won't make the string any shorter). So if this succeeds it'll be a string that's 8,000 characters long. But it gets better because .NET strings are stored internally as UTF-16 which means 2 bytes per character so this string will take up 16KB in memory. On top of the 8KB for your buffer and the 8KB for the tcpClient buffer this one method is already taking up over 32KB.

    To terminate this thread though your code has to marshal this string back to the UI thread using the m_MainWindow.Invoke method (which takes time to enqueue the invocation). So this code will have to run on the same thread as the timer (which means they'll be competing for time and may be blocking each other depending on what you're doing in them). 

    There may be other factors at play here and I'm certainly not able to say that any or all of these things are happening in your code, only highlighting that one or more of them could be happening with disasterous consequences. Your empty catch block doesn't help either.

    I'd need to see much more of your code (maybe your application overall) to help debug this any further but between networking code and threading you're in trecherous waters.


    Anthony D. Green Solution Architect IRC: ##vb.net on FreeNode
    • Marked as answer by Xingwei Hu Thursday, June 4, 2009 7:03 AM
    Saturday, May 30, 2009 7:06 PM
  • Hi,
    A good idea is to use a separate thread to run in a while loop and keep accepting tclclient (if you are expecting more than one). This thread can then instantiate more threads for each connection established. Also make sure that you dispose all unwanted objects. All this networking code needs to be away from the UI code.
    If this post is useful, mark it as answer.
    • Marked as answer by Xingwei Hu Thursday, June 4, 2009 7:03 AM
    Monday, June 1, 2009 1:18 PM

All replies

  • Did you test it already not in a trhread and what was then the result?
    Friday, May 29, 2009 8:21 AM
  • I cannot test without thread because, if I don't use thread there, my form is not responding because it continuously listening to network.
    Friday, May 29, 2009 8:40 AM
  • Then the problem is in my idea that you starts to much threads, while you probably only need one.

    Cor
    • Proposed as answer by Cor Ligthert Friday, May 29, 2009 8:46 AM
    Friday, May 29, 2009 8:46 AM
  • Have you tried it without the error masking?
    Friday, May 29, 2009 8:54 AM
  • Hi Cor Ligthert,

    I have only one thread in my application. I am starting only one thread with the code I posted in my first post.

    Hi JohnWein,

    I have no error masks.

    I don't really understand whether this is the problem with tcpip listener.

    Friday, May 29, 2009 9:23 AM
  • What do you call a Try Catch with an empty Catch?  You are masking errors that are not major enough to cause your app to fail completely.
    Friday, May 29, 2009 9:31 AM
  • Can you show how you start that (not your whole program)?
    Friday, May 29, 2009 10:43 AM
  • Yes, I have an empty Catch statement. But, I am not sure whether that is causing the problem. I'll test and update again.
    Thanks for information. BTW, what will empty Catch will do??
    Friday, May 29, 2009 10:52 AM
  • The problem is most likely in the design of your application. Networking code in .NET can be non-intuitive, I know. Correct my understanding if it's wrong but you have a timer which every second calls the getNetworkRequest method in a different thread? If this is the case then while you may think you're only creating one thread you may be creating 1 every second. Follow me on this logic

    Your timer most likely runs on the UI thread every second. It kicks off new thread A and starts the getNetworkRequest method.

    tcpListener.AcceptTcpClient() method blocks until a request arrives; that is if there isn't one it'll wait forever. If it does wait forever then in a second the timer will kickoff another thread. If there is a connection great.

    tClient.ReceiveBufferSize by default has a size of 8KB so in making an array that large you are allocating another 8KB.
    the networkStream.Read method, not unlike the AcceptTcpClient method will block until either the underlying connection is closed or it fills its buffer. As written you code would only continue if it received a full 8KB of data (or the connection was closed). If this isn't the case it'll hang forever (and in a second another thread will kick off starting this process all over again).

    Dim clientData As String.Encoding.ASCII.GetString(bytes) doesn't tell GetString how many bytes were actually read and just assumes that the entire array is a string, so any extra data will be including in the string as null data (which won't make the string any shorter). So if this succeeds it'll be a string that's 8,000 characters long. But it gets better because .NET strings are stored internally as UTF-16 which means 2 bytes per character so this string will take up 16KB in memory. On top of the 8KB for your buffer and the 8KB for the tcpClient buffer this one method is already taking up over 32KB.

    To terminate this thread though your code has to marshal this string back to the UI thread using the m_MainWindow.Invoke method (which takes time to enqueue the invocation). So this code will have to run on the same thread as the timer (which means they'll be competing for time and may be blocking each other depending on what you're doing in them). 

    There may be other factors at play here and I'm certainly not able to say that any or all of these things are happening in your code, only highlighting that one or more of them could be happening with disasterous consequences. Your empty catch block doesn't help either.

    I'd need to see much more of your code (maybe your application overall) to help debug this any further but between networking code and threading you're in trecherous waters.


    Anthony D. Green Solution Architect IRC: ##vb.net on FreeNode
    • Marked as answer by Xingwei Hu Thursday, June 4, 2009 7:03 AM
    Saturday, May 30, 2009 7:06 PM
  • Hi Anthony D. Green,

    You are right. Now, I understand what mistake I am doing. As what you told, the prbolem is with my timer which is created one thread at every second.
    What if I call my thread at form load and use while loop in my getNetworkRequest method?

    Thanks for your reply!!
    Monday, June 1, 2009 7:27 AM
  • Hi,
    A good idea is to use a separate thread to run in a while loop and keep accepting tclclient (if you are expecting more than one). This thread can then instantiate more threads for each connection established. Also make sure that you dispose all unwanted objects. All this networking code needs to be away from the UI code.
    If this post is useful, mark it as answer.
    • Marked as answer by Xingwei Hu Thursday, June 4, 2009 7:03 AM
    Monday, June 1, 2009 1:18 PM