1

There's probably 20 (or more?) of these questions on stackoverflow, but none of them address what I'm trying to do.

I have an application whose purpose is to receive some data from an outside source through a web service, normalize it and then populate it into a BlockingCollection<T>, to be consumed at a later time when a connection to another web service can be made. The code to receive the data looks like this (it's a Nancy callback):

private dynamic AcceptSignalData(dynamic parameters)
{
    try
    {
        //This call extracts the post body data from the web request. 
        //The post body data contains JSON of the changed signals
        var states = this.Bind< List< SignalStateData > >();

        this._logger.Log(LogSeverity.Debug, string.Format("Received {0} states", states.Count));

        foreach (var state in states.Select(s => new SignalStateData(s.Id, s.Value, s.Timestamp.ToUniversalTime())))
        {
            this._collection.Add(state);
        }
        return this.Response.AsJson(true);

    }
    catch (Exception ex)
    {
        this._logger.Log(LogSeverity.Error, "An error was thrown while extracting received data. The error is as follows:");
        this._logger.Log(LogSeverity.Error, ex);
    }
    return this.Response.AsJson(false);
}

In this case, this._collection is consumed if a connection to the other web service can be made.

A requirement of this is: if the connection cannot be made, the application should simply hold on to the data in this._collection until the cows come home and dispatch when the connection is there. Obviously if it waits to long the application will throw an OutOfMemoryException which is the problem I'm running into.

I'm trying to determine the point at which the OutOfMemoryException will actually occur so I can simply drop the n oldest items from this._collection. I want to find, as a rough percentage, how much memory my process has remaining.

I've used the code from this SO answer but from my understanding, that's the total memory available in the system, which isn't all that useful for my purpose. This is the code I have now, but it produces negative numbers because of the system-wide scope of PerformanceCounter:

/// <summary>
/// The constructor for the <see cref="MemoryManager" /> object.
/// </summary>
public MemoryManager(ILogger logger)
{

    this._memoryCounter = new PerformanceCounter("Memory", "Available Bytes");
    this._memoryCancellationToken = new CancellationTokenSource();
    this._updateMemoryTask = Task.Factory.StartNew(this.UpdateAvailableMemory, this._memoryCancellationToken.Token);
    this._currentProcess = Process.GetCurrentProcess();
    this._logger = logger;

    this.AvailableMemoryPercentage = 100.0F;
}

#endregion
#region Methods

private async void UpdateAvailableMemory(object state)
{
    var token = (CancellationToken)state;

    while (!token.IsCancellationRequested)
    {
        try
        {

            float totalAvailableBytes = this._memoryCounter.NextValue();

            float totalUsedBytes = totalAvailableBytes - this._currentProcess.PrivateMemorySize64;

            this.AvailableMemoryPercentage = Math.Round(totalUsedBytes / totalAvailableBytes * 100, 2);

            var logMessage = string.Format("RAM: {0} MB ({1}%)",
                                (1.0 * totalUsedBytes / 1024 / 1024).ToString("0.##"),
                                this.AvailableMemoryPercentage);

            this._logger.Log(LogSeverity.Info, logMessage);

            await Task.Delay(MEMORYCHECKINTERVAL_MS, token);
        }
        catch (Exception ex)
        {
            this._logger.Log(LogSeverity.Debug, "Exception in memory management:");
            this._logger.Log(LogSeverity.Debug, ex);
        }
    }
}

I don't care how much memory my process is using (well, I guess I do but it's only 50% of the problem); I'm more interested in how much is available. I understand that there's a lot of different angles to this but I'm looking for a very rough estimate.

Community
  • 1
  • 1
Brandon
  • 4,491
  • 6
  • 38
  • 59
  • on x86 2Gb, on x64 all the free ram – Gusman Feb 26 '16 at 16:55
  • Pedantic correction to @Gusman comment - Since OOM mainly caused by exhastion of address space on x86 -you have 2/3/4GB (depending on OS/large-address-aware flag for app), on x64 - almost unlimited (page file will limit really available memory) – Alexei Levenkov Feb 26 '16 at 17:12
  • Can I ask are you really sure you would want your `BlockingCollection` taking up as much RAM as possible? Have you thought about setting a limit on how many items you add before you start removing from the end, or having items timeout? I understand you may wish to track how much memory you are using but I wouldn't think you should try mapping the size of the collection to the amount of memory you application is current taking up. – Stephen Ross Feb 26 '16 at 17:36
  • @StephenRoss Obviously there's other things in my application that take up memory. The `BlockingCollection` just happens to be the largest at any given time due to the amount of items coming from the web service. Over a day or two, it's into the billions. The memory code in my question is not mapped specifically to the `BlockingCollection`. – Brandon Feb 26 '16 at 18:02
  • @Gusman I just tested the application in question while watching memory usage. I got the `OutOfMemoryException` at 1.5GB used. I'm running Windows 7 Ultimate x64. I have 16gb of RAM. – Brandon Feb 29 '16 at 14:19
  • I'm not sure why, but this can be by memory fragmentation, maybe some blocks of ram are being allocated but not fully used. Also, having a list so big in memory is usually not a good design, use an storage buffer (a file, a db or something like that) and process just blocks of data. – Gusman Feb 29 '16 at 14:22

0 Answers0