NETMF 4.3 Debug.GC(false) disposing of Filestream

Morning all,

I have an odd behaviour that has just started on some code that has been working for ages. I load a file (from uSD or USB) and parse it to set up some CAN frames. The following routine is called a few times and has been working fine for ages, with the Debug.Print in place. Now it is throwing an exception.

        private void setUpTxFrames(FileStream dataFile, ref CANMessage[] txFrames)
        {
            int n_Tx = (int)(dataFile.ReadByte());  // 1 Byte = number of CAN messages in setup file
            txFrames = new CANMessage[n_Tx];
            // Index through the setup file and populate the CAN message arrays
            for (int i = 0; i < n_Tx; i++)
            {
                txFrames[i] = new CANMessage();
                txFrames[i].period = (dataFile.ReadByte() * 5); // 1st byte per message is period / 5ms

                // Don't use this byte
                //CANTxMsg[i].MsgData[0].Length = dataFile.ReadByte(); // 2nd byte per message is number of bytes (Length)
                // going to discard it...
                dataFile.ReadByte(); // 2nd byte per message is number of bytes (Length)

                // Next 8 bytes are the CANdata (even if Length < 8)
                byte[] _msgData = new byte[8];
                int readbytes = dataFile.Read(_msgData, 0, 8);
                txFrames[i].setData(_msgData);

                // Read next 4 bytes and convert to uint for ArbitrationId (Message address)
                uint ArbId = (uint)((dataFile.ReadByte() << 24) + (dataFile.ReadByte() << 16) + (dataFile.ReadByte() << 8) + dataFile.ReadByte());
                txFrames[i].setID(ArbId);

                // Read period
                if (txFrames[i].period == 0)
                { txFrames[i].active = false; }

                else
                { txFrames[i].active = true; }

                Debug.Print("After CAN message " + i + " : Mem=" + Debug.GC(false));
                
            }

        }

I load a file from the uSD, and it enters this routine. Typically, there are about 13 CAN frames, so it will step through the main loop shown 13 times. It goes through the first time with no issues. When it reaches the Debug.Print statement, the Debug.GC(false) appears to trigger the system to dispose of the filestream even though I have not closed it myself yet. Then, when I call the Read on the next time through the loop I get an exception saying that the Filestream has been disposed, and a Watch on the dataFile.length (and other parameters) backs this up.

If I comment out the Debug.GC(false), it all works fine.

Oddly, this never happened before , but I have recently modified the way I sense the uSD card is there (check the GPIO pin instead of a Try Catch around the mount), so maybe that is affecting it.
However, my 2 questions are:

  • Should GC dispose of this filestream if I haven’t closed it yet, even if I call Debug.GC?
  • If I call Debug.GC(false) I thought this did not force GC, and just return the free memory?
  • Are there any settings in Visual Studio that affect GC that I may have inadvertently set/reset that could change this behaviour?

For now, I do not need to print the memory here anyway (it was more of a hangover from a previous project with less memory), so this does not block me, but I would like to understand what is happening and check if I am handling the filestream incorrectly.

Thanks

Nick

You are using an object that is no longer referenced. The garbage collector is clearing it. Even if you remove that line, the bug in your code is still there. Any time the garbage collector run you will have a problem.

You need to find that object instance and keep is reference alive.

Thanks Gus,

I suspect my understanding of references still has huge holes in it! I have adjusted the method to pass the filestream object by reference, as that would have been better, but it does not fix it. I also changed the variable name within the method (as I used the same name for datafile both inside and outside the method) just in case that was causing it, but that made no difference either)

I do call this method twice (for CAN 1 and CAN 2) and only then close the filestream.

            // Load CANbus 1 messages
            setUpTxFrames(ref dataFile, ref can1MessagesTx);
            // Load CANbus 2 messages
            setUpTxFrames(ref dataFile, ref can2MessagesTx);

            dataFile.Close();

Would the reference not still exist to the file until I call the Close() function? Or do I have to do something else to keep it alive?

Nick

I am not exactly sure where or how but I would simplify the code to see what exactly is getting disposed. The SD driver, or the media or …

Take CAN and everything else out. I wish I had a direct answer.

Thanks Gus,

No worries - I shall try and isolate it and see what i find!

Nick

where is your filestream initially instantiated. That’s the reference that is likely disposed. Show us that code and it’ll help identify your problem :slight_smile:

Thanks Brett,

I found it :slight_smile:

On the positive side, the reason I couldn’t find anything wrong with my file code was that there wasn’t anything! However, my SD card code was wrong.

I declare

private GHI.IO.Storage.SDCard SDCard;

and use that throughout my code.
But, when trying to get SD card detection to work, I tried all sorts of things and then copy/pasted some of the final working code in to my program, and ended up with this.

        if (!sdCardDetectPin.Read())
        {
            GHI.IO.Storage.SDCard uSDCard = new GHI.IO.Storage.SDCard(); //  This will trigger the Insert event for SD if present
            uSDCard.Mount();
        }

So, I have a completely different variable declared and used to mount the SDCard, whose scope disappears pretty quickly! Hence the GC is disposing of that, and that knocks on to the filestream that is on the SD Card.

Thanks for the help and indulgence for my mistake :slight_smile:

As an aside, the code for detecting SD card at https://old.ghielectronics.com/docs/51/files-and-folders#476 (I don’t know if there is a new ghi website version) has the pullup disabled for the SD detect pin

//Make sure to set the pin to your sd card detect pin.
private static InputPort sdCardDetect = new InputPort(Cpu.Pin.GPIO_NONE, false, Port.ResistorMode.Disabled);

It should have a comment to say that it may need to be set to pull up (at least on the Cobra III) for it to work as well as finding the appropriate GPIO.

Thanks again

Nick

3 Likes