Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory Leak #1

Open
ourcookiemonster opened this issue Aug 11, 2017 · 6 comments
Open

Memory Leak #1

ourcookiemonster opened this issue Aug 11, 2017 · 6 comments

Comments

@ourcookiemonster
Copy link

Greetings Dibyendu,

Thank you for this very useful wrapper to NLopt. I am seeing that there may be a memory leak. When I run .optimize() on a problem with about 1000 variables the program rapidly grows in memory and eventually runs out (around -Xmx16000M)

If this project is still of interest and you are able to take a look I can upload a sample class that demonstrates the issue.

Kind regards,
Richard

@dibyendumajumdar
Copy link
Owner

Sure please post a test case

@ourcookiemonster
Copy link
Author

Thanks Dibyendu,

Here is a source file that replicates the issue.
NLoptOOM.txt

The custom execute methods simply perform calculations and do not allocate any objects, Memory use continues to grow and grow while the optimizer runs and also does not get recaptured after the optimization finishes. Gradient and non-gradient both impacted.

If there is an issue I feel like it ought to be in this function:

double nlopt_minfunc(unsigned n, const double *x,
double gradient, / NULL if not needed */
void *func_data)

Best,
Richard

@dibyendumajumdar
Copy link
Owner

Hi Richard,

Thank you for the test case.

Every time the objective function is called, Java arrays are allocated by the calling JNI wrapper. According to the JNI specs these should be released when the JNI function finishes - and therefore GC'd. I will have to find out how this actually behaves - it may be that the arrays are not being collected.

Could you try calling the System.gc() inside the objective function occasionally to see it if makes a difference?

I will look into this issue over the next few days.

Regards
Dibyendu

@ourcookiemonster
Copy link
Author

Thanks! Indeed the issue appears to have been around garbage collection of those local JNI java arrays. Unless specifically deleted, the java arrays cannot be GC'd until the native method has finished.

http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references

So despite the "callback" C method completing the "base" JNI method (optimize) was still running ... thereby preventing all of those local JNI java arrays from being GC'd which for a large long-runnuing optimization resulted in OOM.

I added the following 2 lines in nlopt_minfunc to dereference those 2 arrays and recompiled nlopt4j.dll:

jni->DeleteLocalRef(xarray);
jni->DeleteLocalRef(gradientarray);
return result;

I enabled the G1 garbage collector and everything looks good now, memory use completely stable!

-Rich

@dibyendumajumdar
Copy link
Owner

Fantastic. I will add these calls.

Thank you very much!

dibyendumajumdar pushed a commit that referenced this issue Aug 22, 2017
@dibyendumajumdar
Copy link
Owner

Hi Richard

I have committed the fix you suggested. I built the library on Windows 10 using VS2017. But I have not yet been able to test it as the Maven build for the Java components doesn't support this version of Visual Studio. If you are able to test this version then please let me know.

Thanks and Regards
Dibyendu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants