Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping Garbage Collection for an unmanaged Delegate

Tags:

c#

.net

r

I've recently been trying out using R.NET to get R talking to .NET and C#. It's been going very well so far, but I've hit a snag that I don't seem to be able to solve.

I've had no issues with simple, basic commands. I made a simple calculator, and something to import data into a data grid. But now I keep getting the following error:

A callback was made on a garbage collected delegate of type 'R.NET!RDotNet.Internals.blah3::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

It began when I tried to repeatedly import a text file, just to test something. I've looked up this error in various ways - after hours of trawling through pages, it seems that there are a number of causes of this type of error. As time has gone on, I've been stripping back my code to more and more simple tasks to try to eliminate possibilities. I've got this now:

 public Form1()
        {
            InitializeComponent();

            REngine.SetDllDirectory(@"C:\Program Files\R\R-2.13.0\bin\i386");
            REngine.CreateInstance("RDotNet");

            using (REngine currentEngine = REngine.GetInstanceFromID("RDotNet"))
            {
                for (int i = 0; i < 1000; ++i)
                {
                    currentEngine.EagerEvaluate("test <- " + i.ToString());

                    NumericVector returned = currentEngine.GetSymbol("test").AsNumeric();

                    textBox1.Text += returned[0];

                }

            }

        }

All it does is increment a count in textBox1.Text. I had been doing it as a test with a button press incrementing the value, but this was making my finger ache after a while! It could typically manage loads of presses before throwing the error above.

At first this code seemed to be fine - so I had assumed the other stuff I had been doing was somehow the cause of the problem, as well as the cause of the error quoted above. So that's why I put in the for loop. The loop can run with no problems for several hundred runs, but then the error kicks in.

Now, I did read that this kind of error can be called by the garbage collector getting rid of the instance I've been working with. I've tried various suggestions that I read, as best I understand them. These have included using GC.KeepAlive() (no luck), and also creating a private field in a separate class that can't be gotten rid of. Sadly this didn't work either.

Is there anything else that I can try? I'm very, very new to C# so I'd appreciate any pointers on how to get this working. I assume very much that my lack of success with the methods suggested are either something to do with (1) my own mistakes in implementing the standard fixes (this seems most likely) or (2) a quirk associated with R.NET that I haven't understood.

Any help would be greatly appreciated!

like image 848
hayward Avatar asked Jun 26 '11 16:06

hayward


People also ask

Can garbage collector claim unmanaged objects?

Although the garbage collector is able to track the lifetime of an object that encapsulates an unmanaged resource, it doesn't know how to release and clean up the unmanaged resource. If your types use unmanaged resources, you should do the following: Implement the dispose pattern.

Can users prevent garbage collection?

Garbage collection is performed automatically. We cannot force or prevent it. Objects are retained in memory while they are reachable. Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole, as we've seen in the example above.

What are the three possible conditions for a garbage collection?

Conditions for a garbage collectionThe system has low physical memory. The memory size is detected by either the low memory notification from the operating system or low memory as indicated by the host. The memory that's used by allocated objects on the managed heap surpasses an acceptable threshold.

Can garbage collection be forced?

If you want to force garbage collection you can use the System object from the java. lang package and its gc() method or the Runtime. getRuntime(). gc() call.


2 Answers

Looks like a bug in R.NET. The exception you're seeing happens when a .NET layer passes a callback to unmanaged code but then lets the delegate get garbage collected. I see no delegate usage in your repro code, hence the conclusion that it must be in R.NET.

like image 65
Stephen Cleary Avatar answered Oct 04 '22 14:10

Stephen Cleary


As Stephen had suggested, it turns out it was a bug in the version of R.NET that I was using, and not an error in what I was doing (which was my original guess, hence my reason for posting here!). The author of R.NET has replied to my post on the R.NET forums, and has fortunately already solved this issue and updated R.NET, though not in the form of a dll just yet (it's easy enough to import the source files though).

I can confirm that the latest version of the source files do in fact not suffer from this problem. Hurrah! Thanks to all those who replied here. It's unfortunate that I spent so long scratching my head over a simple bug, but it was helpful in getting to know more C# / .NET stuff while I was searching for a solution.

like image 31
hayward Avatar answered Oct 04 '22 14:10

hayward