asynchronously release SymbolicExpression #149
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hello !
We are currently working with RDotNet 1.9.0 / R 4.1.2 / .NET Framework 4.7 / Windows ,
but we have had some strange behaviour, our process was randomly stucked on a RDotNet method call but inside the R.dll
(active loop, 100% CPU load)
Here is a part of the stack:
R.dll!Rf_pmatch+0x32da
R.dll!Rf_allocVector3+0x2d0
R.dll!Rf_allocMatrix+0x36
R.dll!rwarn_+0xa1c6
R.dll!rwarn_+0xfe0c
R.dll!R_BadLongVector+0x17f
R.dll!R_initAssignSymbols+0x745b
R.dll!Rf_eval+0x171
For an unknown reason (compilation option?) the symbols were not correct, so after a few logs added in r.dll
It appears that R was stucked in r-source/src/main/memory.c/RunGenCollect
Not always exactly the same line, but it looked like some kind of corruption of R internal structure
After a "few" other tests, it was finally reproducible more often (see CreateStressTest below)
It is a quick loop of REngine.Evaluate which often gives AccessViolationException or sometimes it is stucked in the R garbage step.
The problem seems to come from SymbolicExpression.
Preserve method is called in constructor and_Unpreserve_ method is called in the ReleaseHandle,
but as it is a SafeHandle and Dispose is never called, ReleaseHandle method is called in another thread of the VM which is dedicated to finalization process.
So we may have 2 different threads accessing the R.dll
Unfortunately, in Expression.TryEvaluate there is a call to R_tryEval from R.dll which is not locked.
And since R-4.1.2 there has been changes in R_tryEval (now it uses R_PreserveObject and R_ReleaseObject)
It happens with R-4.1.2 / R-4.0.2 (windows and linux version)
So here is a possible fix:
add a lock on Expression.TryEvaluate,
as we dont want to lock and block the GC Finalizer thread for a long time, do the release in another thread.
Another possible fix could have been to explictly call Dispose on each SymbolicExpression (so they cant be called from another thread) and that the caller of REngin.Evaluate do the same with the SymbolicExpression result)
But there are a lot of SymbolicExpression creation and maybe it would be less readable, for example in Parse method:
It could be the same issue than here: #133