使用串行端口,我收到一个错误:尝试读取或写入受保护的内存

问题描述 投票:0回答:2

我知道之前已经问过这个问题,但现有的答案都没有解决我的问题。我有一个WinForms应用程序,它与许多设备通信,获取数据并将它们写入文件。

它打开GPIB和串口通信,最后关闭所有这些通信。我使用this.Dispose()this.Close()来确保释放内存(至少我认为内存已被释放)。但是,下次我运行它,几个小时后我收到错误:

尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

如果我再次运行它,崩溃时间会越来越短,就像内存中积累的东西一样。我复制了与此问题相关的部分代码。我在内存消耗方面有任何错误吗?

我尝试了什么:

添加了this.Dispose()Close()函数来关闭端口(最初我忘了添加它们)。但仍然没有帮助。我还尝试在每次运行之前重新启动计算机,但它也没有帮助。

public partial class Form1 : Form
{
    //GPIB and serial ports
    SerialPort Arduino;
    SerialPort serialPort1 = new SerialPort();
    private Device DMM1, DMM2, DMM3;
    private Address DMM1_Address, DMM2_Address, DMM3_Address;
    private Address[] Address_List = new Address[3];
    private AddressCollection GPIB_Adds;
    Board GPIB = new Board(0);
    //Timers
    System.Windows.Forms.Timer fire_time = new System.Windows.Forms.Timer();
    System.Windows.Forms.Timer measurement_time = new System.Windows.Forms.Timer();
    System.Windows.Forms.Timer preparation_delay = new System.Windows.Forms.Timer();
    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();

    public Form1()
    {
        // ...some code
    }

    private void InitializePorts()
    {
        // ...ports are initialized here
    }


    private void button1_Click(object sender, EventArgs e)
    {
       preparation_delay.Interval = 1000;
       preparation_delay.Tick += new EventHandler(start);
       preparation_delay.Start();

       measurement_time.Interval = 60000;
       measurement_time.Tick += new EventHandler(stop);

       fire_time.Interval = Convert.ToInt32(textBox6.Text) * 1000;
       fire_time.Tick += new EventHandler(FIRE);
        }
    }

    private void start(object obj, EventArgs e)
    {
        stopwatch.Start();
        measurement_time.Start();
        fire_time.Start();
        preparation_delay.Stop();
        preparation_delay.Tick -= new EventHandler(start);
        //Here I try to annihilate the event handler in fear of staying in memory
    }

    private void FIRE(object obj, EventArgs e)
    {
        string p = //Reads data from device
        string[] k = //Reads data from device
        string t = //Reads data from device
        Write_to_Text(t, p, k);
    }

    private void stop(object obj, EventArgs e)
    {
        fire_time.Stop();
        measurement_time.Stop();
        progress.Stop();
    }

    private void Write_to_Text(string time_date, string PRC_Reading, string[] DMM_Reading)
    {
        string string_to_save =  ...some string

        try
        {
            System.IO.File.AppendAllText(@filename, string_to_save);
        }
        catch (Exception ex)
        {
            serialPort1.Close();
            Arduino.Close();
            GPIB.Dispose();

            measurement_time.Stop();
            fire_time.Stop();
            this.Dispose();
            this.Close();
        }
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        serialPort1.Close();
        Arduino.Close();
        GPIB.Dispose();

        this.Dispose();
        this.Close();
    }
}
c# .net winforms serial-port
2个回答
0
投票

原则上,对于本机NET对象,您不需要显式调用Dispose(终结器将执行此操作),但如果您有一些外部对象访问外部资源(GPIB?),则必须小心。我看到的是,如果Write_To_Text中存在异常,您将调用GPIB.Dispose两次,并且还可以在定时器有效停止之前调用它。确保在处理之后不会调用任何Gpib函数(例如,设置一个在调用Gpib函数之前将检查的标志)。


0
投票

每当你发现自己手动调用Dispose()函数时,这有点代码味道......这表明某些事情是不对的。

相反,学习使用using关键字来创建包装一次性对象的块。这将帮助您为这些对象创建有意义的范围边界。它还有助于避免错误,其中Close()Dispose()调用没有用finally块正确包裹。

在这种情况下,问题可能涉及以下代码段:

this.Dispose();
this.Close();

永远不要从你想要处理的对象内部调用Dispose()(除了作为实现核心IDisposable模式的一部分)。相反,它取决于外部代码,告诉您的对象何时完成。在这里,你尝试在引发Dispose()方法之前Form_Closing表格(参见Write_To_Text()),这意味着当Form_Closing()本身试图执行时表单无效。

© www.soinside.com 2019 - 2024. All rights reserved.