HTTPServer example causes memory leak

When I try to run the HTTPServer example from HTTP/HTTPS I get an increasing use of memory that will eventually lead to an OutOfMemory exeption.

Server code:

Can you please try to reproduce and advice on what to do?

Edit: I am using the Fez Portal and connect via wifi.

Here is the client code:

image

Could you paste code as text, not image

We would like to have exactly your code and save our time :)).

Hi, absolutely.

Server code:

            //Create a listener.
            HttpListener listener = new HttpListener("http", 80);

            listener.Start();
            Debug.WriteLine("Listening...");

            var clientRequestCount = 0;

            while (true)
            {
                //Note: The GetContext method blocks while waiting for a request.
                HttpListenerContext context = listener.GetContext();

                //Obtain a response object.
                HttpListenerResponse response = context.Response;

                //Construct a response.
                System.GC.Collect();
                var freeRam = GHIElectronics.TinyCLR.Native.Memory.ManagedMemory.FreeBytes;
                var responseString = string.Format("<HTML><BODY> I am TinyCLR OS Server. " + "Client request count: {0}, FreeRAM: {1}</BODY></HTML>", ++clientRequestCount, freeRam);
                Debug.WriteLine(responseString);
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

                //Get a response stream and write the response to it.
                response.ContentLength64 = buffer.Length;
                var output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);

                //You must close the output stream.
                output.Close();
            }

            listener.Stop();

Client code:

                // Create the URL
                Uri address = new Uri("http://192.168.1.105");

                // Create request
                HttpWebRequest request = HttpWebRequest.Create(address) as HttpWebRequest;

                request.Method = "GET";
                request.Timeout = 5000;
                request.KeepAlive = false;

                // Get response  
                string responseString;
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    using (var stream = new StreamReader(response.GetResponseStream()))
                    {
                        responseString = stream.ReadToEnd();
                    }
                }

Thanks, add these in your while loop, doesn’t matter where, but recommend end of loop.

               ............  
               //You must close the output stream.
                output.Close();

                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();

Or if you don’t want GC every message, you can do

const int RAM_UNDER_THRESHOLD = 150 * 1024

.......
if (freeRam < RAM_UNDER_THRESHOLD ) {
          System.GC.Collect();
          System.GC.WaitForPendingFinalizers();
}

Thanks, that works! But should I really have to do this? I though the GC would take care of this when the system was running low on memory?

1 Like

Yes, but

I would like to move GC/Finalize to end of loop.

But I don’t mind if your code makes you happy.

I found some that if you close the Response instead of the Output, there is no issues with the memory and no need to force the GC to wait for the finalizers. Also the code executes much faster. So I would suggest that you change your example code to closing the Response:

        //Create a listener.
        HttpListener listener = new HttpListener("http", 80);

        listener.Start();
        Debug.WriteLine("Listening...");

        var clientRequestCount = 0;

        while (true)
        {
            try
            {
                //Note: The GetContext method blocks while waiting for a request.
                HttpListenerContext context = listener.GetContext();

                //Obtain a response object.
                HttpListenerResponse response = context.Response;

                //Construct a response.
                System.GC.Collect();
                var freeRam = GHIElectronics.TinyCLR.Native.Memory.ManagedMemory.FreeBytes;

                var responseString = string.Format("<HTML><BODY> I am TinyCLR OS Server. " + "Client request count: {0}, FreeRAM: {1}</BODY></HTML>", ++clientRequestCount, freeRam);
                Debug.WriteLine(responseString);
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

                //Get a response stream and write the response to it.
                response.ContentLength64 = buffer.Length;
                var output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);

                // When you close the response all the streams are closed and released.
                response.Close();
            }
            catch (Exception)
            {

            }
        }

I will move the other question to a separate thread.

Sure, once you tested and no other issues, we will update our doc.

Thanks for help

Here is the debug output when closing the Output:

IP Adress:192.168.1.105, RSSI: 78
Listening…
The thread ‘’ (0x3) has exited with code 0 (0x0).

I am TinyCLR OS Server. Client request count: 1, FreeRAM: 330320 I am TinyCLR OS Server. Client request count: 2, FreeRAM: 325808 #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (6) #### #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 3, FreeRAM: 325152 I am TinyCLR OS Server. Client request count: 4, FreeRAM: 323088 #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (6) #### #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 5, FreeRAM: 323088 I am TinyCLR OS Server. Client request count: 6, FreeRAM: 320976 #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (6) #### #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 7, FreeRAM: 320848 I am TinyCLR OS Server. Client request count: 8, FreeRAM: 319008 #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (6) #### #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 9, FreeRAM: 318304 I am TinyCLR OS Server. Client request count: 10, FreeRAM: 316432 #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (6) #### #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 11, FreeRAM: 317040 #### Message: #### System.Net.OutputNetworkStreamWrapper::Flush [IP: 0014] #### #### System.Net.HttpListenerResponse::System.IDisposable.Dispose [IP: 0018] #### Exception thrown: 'System.NullReferenceException' in GHIElectronics.TinyCLR.Networking.Http.dll I am TinyCLR OS Server. Client request count: 13, FreeRAM: 314416 I am TinyCLR OS Server. Client request count: 14, FreeRAM: 312544

An exception is thrown somewhere, but it is caught.

Here is the debug output when closing the Response:

IP Adress:192.168.1.105, RSSI: 76
Listening…
The thread ‘’ (0x3) has exited with code 0 (0x0).

I am TinyCLR OS Server. Client request count: 1, FreeRAM: 333536 I am TinyCLR OS Server. Client request count: 2, FreeRAM: 329808 I am TinyCLR OS Server. Client request count: 3, FreeRAM: 330112 I am TinyCLR OS Server. Client request count: 4, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 5, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 6, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 7, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 8, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 9, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 10, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 11, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 12, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 13, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 14, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 15, FreeRAM: 330176 I am TinyCLR OS Server. Client request count: 16, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 17, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 18, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 19, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 20, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 21, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 22, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 23, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 24, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 25, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 26, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 27, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 28, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 29, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 30, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 31, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 32, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 33, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 34, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 35, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 36, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 37, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 38, FreeRAM: 330496 I am TinyCLR OS Server. Client request count: 39, FreeRAM: 330496

After a while it stabalizes at 332480 free RAM.

1 Like

Thanks, our team will check it soon:

HTTP server: Replace closing stream by response object · Issue #716 · ghi-electronics/Documentation (github.com)

Hi, I have done some more investigation into this issue and I believe I have found the root cause for this. When OutputNetworkStreamWrapper.Close is called, some fields are set to null. When the parent, HttpListenerResponse, is disposed, it tries to flush and dispose the OutputNetworkStreamWrapper. This will lead to a NullException in the HttpListenerResponse.Dispose method, so the object is not disposed of correctly.

So instead of changing the documentation, I suggest we fix the problem instead.

I also found some other issues with the HTTP classes that should be fixed. I will create issues and PR’s for this on your GitHub repo.

Issue created: Memory not collected after calling OutputNetworkStreamWrapper.Close · Issue #1222 · ghi-electronics/TinyCLR-Libraries · GitHub