问题
I know this question has been asked before but none of the existing answers solved my problem. I have a WinForms Application which communicates with a number of devices, takes data and writes them to a file.
It opens GPIB and Serial port communications and at the end closes all of them. I use this.Dispose() and this.Close() to make sure that memory is released (at least I think the memory is released). However, next time I run it, after several hours I get the error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
If I run it again the crash time becomes shorter and shorter as if something is accumulating in memory. I copy parts of my code that seem to be related to this issue. Am I making any mistake in memory consumption?
What I tried:
Added this.Dispose() and the Close() functions to close the ports (initially I forgot to add them). But still did not help. I also tried to restart my computer before each run, yet it did not help either.
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();
}
}
回答1:
For native NET objects in principle you don't need to call Dispose explicitly (the finalizer will do that), but if you have some external objects accessing external resources (GPIB?) you have to be careful. What I see is that if there is an exception in Write_To_Text you will call GPIB.Dispose twice, and also that it can be called before the timers effectively stop. Make sure that there will be no call to any Gpib function after you dispose it (for example set a flag that will be checked before calling Gpib functions).
回答2:
Whenever you find yourself manually calling the Dispose() function, that's a bit of a code smell... an indication something is not right.
Instead, learn to use the using keyword to create blocks that wrap disposable objects. This will help you create meaningful scope boundaries for the those objects. It also helps avoid mistakes, where Close() and Dispose() calls were not properly wrapped with a finally block.
In this case, the problem likely involves these code snippets:
this.Dispose();
this.Close();
Never call Dispose() from inside the object itself you want to dispose (except as part of implementing the core IDisposable pattern). Instead, it's up to the outside code to tell your object when it's finished. Here, you attempt to Dispose() a form before the Form_Closing method is raised (see Write_To_Text()), meaning the form is invalid when Form_Closing() itself tries to execute.
来源:https://stackoverflow.com/questions/50253977/using-serial-ports-i-get-an-error-attempted-to-read-or-write-protected-memory