Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutOfMemoryException when reading a string

I have a C# .NET system that takes a JSON data feed and converts it to an object using the Newtonsoft.Json.JsonConvert.DeserializeObject converter.

This process works perfect as long as the JSON string is below a certain size (a few Mb) but as soon as the returned data is large (almost 100Mb) I get the error OutOfMemoryException

This code works great for small data:

// WebClient ------------------------------------------------------------------
var _client = new System.Net.WebClient();
var _content = _client.DownloadString(_url);

but blows up on the last line (DownloadString)

I tried changing to this which also works for small data but it still blew up on the ReadToEnd line when the data grew in size.

using (var _response = (System.Net.HttpWebResponse)_request.GetResponse())
{
    using (System.IO.Stream _dataStream = _response.GetResponseStream())
    {
        using (System.IO.StreamReader _streamReader = new System.IO.StreamReader(_dataStream))
        {
            string _responseFromServer = _streamReader.ReadToEnd();
        }
    }
}

Finally I tried this which worked:

StringBuilder _stringBuilder = new StringBuilder();
using (var _response = (System.Net.HttpWebResponse)_request.GetResponse())
{
    using (System.IO.Stream _dataStream = _response.GetResponseStream())
    {
        using (System.IO.StreamReader _streamReader = new System.IO.StreamReader(_dataStream))
        {
            while (!streamReader.EndOfStream)
            {
                char[] _buffer = new char[4096];
                _streamReader.ReadBlock(_buffer, 0, _buffer.Length);
                var _bufferString = new String(_buffer);
                _stringBuilder.Append(_bufferString);
            }
        }
    }
}

But it blew up with an OutOfMemoryException error when it got to the next line here:

var _results = Newtonsoft.Json.JsonConvert.DeserializeObject<List<MyObject>>(_stringBuilder.ToString());

It didn't like the ToString() method.

It also crashed with a simple line like

string _convertedString = _stringBuilder.ToString();

The full error is:

An exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll but was not handled in user code

The machine is running 64bit windows with 16Gb of memory.

So, what are my options?

All I want is an IQueryable<MyObject> from a (very large) JSON string.

like image 724
DeclanMcD Avatar asked Dec 23 '15 13:12

DeclanMcD


People also ask

How do you avoid OutOfMemoryException?

Well, according to the topic of the question, best way to avoid out of memory exception would be not to create objects that fill in that memory. Then you can calculate the length of your queue based on estimate of one object memory capacity. Another way would be to check for memory size in each worker thread.

What causes OutOfMemoryException?

When data structures or data sets that reside in memory become so large that the common language runtime is unable to allocate enough contiguous memory for them, an OutOfMemoryException exception results.

What is exception of type system OutOfMemoryException was thrown?

An OutOfMemoryException exception has two major causes: You are attempting to expand a StringBuilder object beyond the length defined by its StringBuilder. MaxCapacity property. The common language runtime cannot allocate enough contiguous memory to successfully perform an operation.

Why do I get an outofmemoryexception when I run a string?

Working with large data sets requires a huge amount of memory and if CLR does not have enough contiguous space available for it then it results in OutOfMemoryException. As strings are immutable, the operations performed on string create a new string in the memory.

How do you catch an out of memory exception in C?

catch(OutOfMemoryException exception) {//statements to handle the exception} The syntax to throw an OutOfMemoryException in C# is as follows: throw new OutOfMemoryException(); In the above statement ‘throw’ is the keyword which is used to throw exceptions in C#.

Why is an outofmemoryexception thrown when calculating the mean?

The output from the example shows that, because the example stores the entire array in memory before it calculates the mean, an OutOfMemoryException is thrown. using System; using System.Collections.Generic; public class Example { public static void Main() { Double [] values = GetData (); // Compute mean.

What is the value of outofmemoryexception in Java?

OutOfMemoryException uses the HRESULT COR_E_OUTOFMEMORY, which has the value 0x8007000E. For a list of initial property values for an instance of OutOfMemoryException, see the OutOfMemoryException constructors. The value of the inherited Data property is always null.


1 Answers

Your code essentially emulates what StreamReader.ReadToEnd does, taking at least 4 times the memory needed to read a large response (the memory of the string response itself, the StringBuilder's internal buffer, the size of all the intermediate temporary strings and the final string).

You can avoid this by deserializing from the stream directly with a JsonTextReader. Copying from the documentation sample:

using (var json= new JsonTextReader(streamReader))
{
    JsonSerializer serializer = new JsonSerializer();
    return (List<MyObject>)serializer.Deserialize(json, typeof(List<MyObject>));
}

O

like image 105
Panagiotis Kanavos Avatar answered Oct 23 '22 00:10

Panagiotis Kanavos