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!
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With