Shaul Zuarets
Shaul Zuarets

Reputation: 849

Every week I get System.OutOfMemoryException: Out of memory

I have a program (C#) that communicate with embedded controller (Modbus), receiving data and log it to a data base. also, it shows the data in a user interface.

Every 5 or 8 days the program crashes (on every computer).

most of the time with no Exception and only the Windows default message "'program name' has stop working".

every once and a while I get the 'System.OutOfMemoryException: Out of memory.' Exception. The program, I'm assume is not designed well because the memory usage is increasing all the time.

After a week it reaches 800Mb.

Is this the problem?

I have tried reset the program every day. It didn't solve the problem.

This is the source:

namespace AtRegisterData
{
    public class RegisterDataManager
{
    modbus mb;

    public RegisterDataManager()
    {
        try
        {
            mb = new modbus();
        }
        catch (Exception ex)
        {
            writeError(ex.Message);
        }
    }
    public static bool systemOnOffStatus = false;
    public static short systemOnOffState = 0;
    public static short reactorNum = 0;
    public int openCom(ReactorConfig reactorData)
    {
        try
        {
            if (mb.Open(Convert.ToString(ReactorConfigManager.ModBusConfiguration.com_port), Convert.ToInt32(ReactorConfigManager.ModBusConfiguration.ModBusBaudRate), 8, ReactorConfigManager.ModBusConfiguration.parity, ReactorConfigManager.ModBusConfiguration.stopBit))
            {
                return 1;
            }
            else
            {
                return 0;       // No connection
            }
        }
        catch (Exception ex)
        {
            writeError(ex.Message);
            return 0; 
        }
    }
    public int CheckConnection(ReactorConfig reactorData)
    {
        try
        {
            // Needs to take the function data from public struct
            if (mb.Open("com20", 115200, 8, Parity.None, StopBits.One))
            {
                return 1;
            }

            // Needs to take the function data from public struct
            if (mb.Open("com1", 9600, 8, Parity.None, StopBits.One))
            {
                return 1;
            }
            else
            {
                return 0;       // No connection
            }
        }
        catch (Exception ex) 
        { writeError(ex.Message); 
            return 0; }
    }
    public List<ReactorEvent> getEvents(ReactorConfig reactorData)
    {
        try
        {
            ushort registerNum;
            List<ReactorEvent> eventsList = new List<ReactorEvent>();
            // List that will hold all of the data (all the registers)
            List<ushort> registerValues;
            // Get's the data from the modbus

            for (int i = 0; i < ReactorEventConfigManager.ReactorEvents.Count; i++)
            {
                registerNum = Convert.ToUInt16(ReactorEventConfigManager.ReactorEvents[i].ModBusRegisterNumber); // Convert the register numb to Unsigned short
                registerValues = new List<ushort>(); // Initlize the list
                try
                {
                    mb.SendFc3(reactorData.ModBusAddress, registerNum, 1, registerValues);
                }
                catch
                {
                    throw new NoConnectionException();
                    i = ReactorEventConfigManager.ReactorEvents.Count;
                }

                if (registerValues.Count > 0 && registerValues[0] == ReactorEventConfigManager.ReactorEvents[i].onFlag) // If the event is on?{eventsList.Add(ReactorEventConfigManager.ReactorEvents[i]);}
                {
                    eventsList.Add(ReactorEventConfigManager.ReactorEvents[i]);
                }
            }
            return eventsList;
        }
        catch (Exception ex)
        { writeError(ex.Message);
            return null; }
    }
    /// <summary>
    /// Reads data from the controller
    /// </summary>
    /// <param name="reactorNumber">the reactor's ndbuumber</param>
    /// <returns></returns>
    public Dictionary<Register, string> ReadData(ReactorConfig reactorData, List<short> unitedRegisters)
    {
        try
        {

            //Register tempRegister = new Register();
            Dictionary<Register, string> returnData = new Dictionary<Register, string>();
            string strRegisterValue;
            int registerLocation = 0;
            List<ushort> registerValues = new List<ushort>();                                         // List that will hold all of the data (all the registers)
            List<ushort> registerValuesNew = new List<ushort>();
            List<bool> coilsValues = new List<bool>();
            ushort startRegister, endRegister, midRegister;
            startRegister = endRegister = midRegister = 0;
            if (getStartAndEndReg(ref startRegister, ref endRegister, LoggerConfigManager.LoggerConfiguration.RegistersToLog) == 1)
            {
                try
                {
                    if (endRegister >= 125)
                    {
                        midRegister = Convert.ToUInt16(endRegister - 124);
                        mb.SendFc3(reactorData.ModBusAddress, startRegister, 125, registerValues);   // Get's the data from the modbus
                        mb.SendFc3(reactorData.ModBusAddress, 125, midRegister, registerValuesNew);   // Get's the data from the modbus

                        if ((systemOnOffStatus == true) && (reactorNum == reactorData.Number))
                        {
                            shutdownLamp(reactorData, systemOnOffState);
                            systemOnOffStatus = false;
                        }

                        for (int t = 0; t <= registerValuesNew.Count - 1; t++)
                        {
                            registerValues.Add(registerValuesNew[t]);
                        }
                    }
                    else
                    {
                        mb.SendFc3(reactorData.ModBusAddress, startRegister, endRegister, registerValues);   // Get's the data from the modbus
                        if ((systemOnOffStatus == true) && (reactorNum == reactorData.Number))
                        {
                            shutdownLamp(reactorData, systemOnOffState);
                            systemOnOffStatus = false;
                        }
                    }
                }
                catch (Exception ex)
                {

                    systemOnOffStatus = false;
                    writeError(ex.Message);
                    throw new NoConnectionException();

                }



                // This loop will organize all of the data received from the modbus in a dictionary
                for (int i = 0; i <= registerValues.Count - 1; i++)
                {
                    registerLocation = findRegisterLocationInList(startRegister + i, LoggerConfigManager.LoggerConfiguration.RegistersToLog);   // Finds the register to copy by the register number
                    if (registerLocation != -1)
                    {
                        Register tempRegister = new Register();
                        copyRegisterData(tempRegister, LoggerConfigManager.LoggerConfiguration.RegistersToLog[registerLocation]);   // Copy the register Info
                        if (isRegisterInlist(tempRegister.RegisterNumber, unitedRegisters))                                         // Check if I need to unite to register to 1 4 byte variant
                        {
                            strRegisterValue = Convert.ToString(get4Byte(registerValues[i], registerValues[i + 1]));               // Unite 2 registers to 4 byte
                            i += 1;                                                                                                 // Need to skip the next register
                        }
                        else
                        {
                            if (tempRegister.DivideBy != null && tempRegister.DivideBy.HasValue)
                                strRegisterValue = Convert.ToString((double)registerValues[i] / tempRegister.DivideBy);
                            else
                                strRegisterValue = Convert.ToString(registerValues[i]);
                        }
                        returnData.Add(tempRegister, strRegisterValue);
                    }// Insert the data into dictionary
                }



                return returnData;
            }
            throw new NotImplementedException();
        }
        catch (Exception ex)
        {
            writeError(ex.Message);
            return null;
        }
    }

Upvotes: 0

Views: 983

Answers (4)

Shaul Zuarets
Shaul Zuarets

Reputation: 849

So, after using dotTrace as suggested, I was able to find the memory leak. It was in this function which called by a timer: private void UpdateEventsScreen() {

        int selectedRow = 0;
        try
        {

            if (EventsDataGrid.Rows.Count > 0)
                selectedRow = EventsDataGrid.SelectedRows[0].Index;

            viewModel = new EventsViewModel();
            EventsViewModelSource.DataSource = viewModel;

            if (EventsDataGrid.Rows.Count > 0)
            {
                EventsDataGrid.Rows[selectedRow].Selected = true;
                NoteValueLabel.Text = viewModel.Events[selectedRow].Note;
            }
        }
        catch{}
    } 

I don't know why, but the line:

viewModel = new EventsViewModel();

cause the memory leak. I thought the garbage collector should handle this. Isn't it? Well, it didn't.

Thanks you all. You helped a lot.

Upvotes: 0

S.Spieker
S.Spieker

Reputation: 7365

Take a look at all unmanaged ressources. If it is da DirectX app make sure you release all resources by hand. All Resources which are of type IDisposable should be disposed. Another starting point would be to check your Serializer, if you have a XmlSerializer for example.

I like the Red Gate Memory Profiler, there is a 14 day trial version available: http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

Upvotes: 0

Michael
Michael

Reputation: 557

Without seeing any source code I highly suspect you are not collecting garbage very well. You should always clean up after yourself in every method, ESPECIALLY in applications that run all the time. Always Dispose() of classes and other variables when done with them. Connections to SQL objects should be closed after data is exchanged. Any open files (IO) should be closed as well, and any external threads/processes called should be terminated.

If any of these are not done then your program will accumulate memory usage fast, and eventually collapse.

Upvotes: 0

meilke
meilke

Reputation: 3280

Run the program for 5 - 8 days using a memory profiler like dotTrace. This will give you a log of what was actually eating up your memory. Everything else is just guesswork.

Upvotes: 5

Related Questions