0

我有一个程序(C#)与嵌入式控制器(Modbus)通信,接收数据并将其记录到数据库中。此外,它在用户界面中显示数据。

每隔 5 或 8 天,程序就会崩溃(在每台计算机上)。

大多数时候没有异常,只有 Windows 默认消息“'程序名称'已停止工作”。

每隔一段时间,我就会收到“System.OutOfMemoryException:内存不足”。例外。我假设该程序设计得不好,因为内存使用量一直在增加。

一周后,它达到 800Mb。

这是问题吗?

我每天都尝试重置程序。它没有解决问题。

这是来源:

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;
        }
    }
4

4 回答 4

5

使用像dotTrace这样的内存分析器运行程序 5 到 8 天。这将为您提供实际消耗内存的日志。其他一切都只是猜测。

于 2013-09-15T09:47:15.457 回答
0

因此,按照建议使用 dotTrace 后,我能够找到内存泄漏。正是在这个由计时器调用的函数中: 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{}
    } 

我不知道为什么,但是这条线:

viewModel = new EventsViewModel();

导致内存泄漏。我认为垃圾收集器应该处理这个问题。不是吗?好吧,它没有。

谢谢大家。你帮了很多忙。

于 2013-09-16T21:47:12.983 回答
0

查看所有非托管资源。如果它是 DirectX 应用程序,请确保您手动释放所有资源。所有 IDisposable 类型的资源都应该被处理掉。另一个起点是检查您的序列化器,例如,如果您有 XmlSerializer。

我喜欢 Red Gate Memory Profiler,有 14 天试用版: http ://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

于 2013-09-15T12:02:55.700 回答
0

在没有看到任何源代码的情况下,我高度怀疑您没有很好地收集垃圾。您应该始终在每种方法中自行清理,特别是在一直运行的应用程序中。处理完类和其他变量时,总是 Dispose()。交换数据后,应关闭与 SQL 对象的连接。任何打开的文件 (IO) 也应该关闭,并且任何调用的外部线程/进程都应该终止。

如果其中任何一个没有完成,那么您的程序将快速累积内存使用量,并最终崩溃。

于 2013-09-15T09:56:56.553 回答