Skip to content

Memory leak when using jscip.MessageHandler #53

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

Open
patrickguenther opened this issue Nov 27, 2024 · 5 comments
Open

Memory leak when using jscip.MessageHandler #53

patrickguenther opened this issue Nov 27, 2024 · 5 comments

Comments

@patrickguenther
Copy link

It's not a large leak but could become a nuisance for long running applications that solve many optimization problems.

The leak was discovered by accident, while debugging an entirely different issue. The attached screenshot shows a heap dump of our application created by visualvm.

image

The number of retained ScipMessageHandler instances only goes up while running more optimization problems and never down even after explicitly invoking garbage collection.

The generated code for jscip.MessageHandler has a close method with an empty body defined. I guess the expected behavior would be that it frees _messagehdlrptr somehow? Or do I need to call some other JSCIP method to free it?

In the meantime, workarounds are:

  • ignore the problem as the leak is not that large
  • don't use message handlers
@kkofler
Copy link
Collaborator

kkofler commented Nov 29, 2024

Something somewhere needs to be deleted indeed, but I do not think close() is the right place. (Note also that jscip.MessageHandler is not generated, it is a wrapper around the generated ObjMessagehdlr and SWIGTYPE_p_SCIP_Messagehdlr classes.)

Try adding this to the anonymous ObjMessagehdlr subclass in MessageHandler.java (i.e., before line 41):

        @Override
        public synchronized void delete() {
          super.delete();
          swigTakeOwnership();
        }

That should clear the reference to the ObjMessageHdlr subclass instance created by the objmessagehdlr.swigReleaseOwnership(); in line 42 when the underlying C++ object is deleted (because, through C++ virtual destructors, that ends up calling ObjMessageHdlr.swigDirectorDisconnect via JNI, which then calls ObjMessageHdlr.delete). So then the nested class should be possible to garbage-collect, which in turn clears the reference to the containing MessageHandler class and should allow that, too, to be garbage-collected.

@patrickguenther
Copy link
Author

So the solution mentioned doesn't seem to work. The delete, finalize or MessageHandler::scip_free methods are just never getting called as can be verified with a debugger.

I don't think it's the user's responsibility to call SCIPJNIJNI::SwigDirector_ObjMessagehdlr_scip_free wich in turn calls ObjMessagehdlr::scip_free since I don't have a reference on that ObjMessagehdlr?
Overall, in my own code I simply instantiate my own MessageHandler class which extends jscip.MessageHandler and overwrites the error, warning, dialog and info methods and attach it to my Scip instance using setMessageHandler. Do I need to call some cleanup methods myself after using it?

I guess I'll have to dive into the SCIP code now to see under which circumstances SCIP deletes my message handler.

@patrickguenther
Copy link
Author

The finalize method is executed by the jvm and the memory cleaned up if I simply remove objmessagehdlr.swigReleaseOwnership(); on line 42 of the MessageHandler class.
image

My knowledge about SWIG and JNI is rather limited, so I'm not familiar with all the repercussions of this change. My higher level app at least doesn't crash, I'm still getting the SCIP info logs and according to visualvm this specific memory leak is gone. I'm going to run some more tests with that throughout the week and see how it goes.

patrickguenther added a commit to patrickguenther/JSCIPOpt that referenced this issue Dec 2, 2024
@kkofler
Copy link
Collaborator

kkofler commented Dec 2, 2024

SCIP is supposed to call scip_free on the MessageHandler if you delete the scip object (call the delete() method on the Java object) or if you set another message handler. If not, this is a SCIP bug.

I believe that your proposed fix is unsafe because, as I understand it, the garbage collector can then destroy your message handler at any time, and then SCIP will call into a freed object, a classic use-after-free crash.

@patrickguenther
Copy link
Author

I see. In my particular case, it doesn't happen, because I always keep a handle on my message handler, because the API I'm implementing assumes, a user can register multiple message handlers that work independently of each other. But in general, you might have a point.

I glanced through the source code of SCIP and JSCIP, and I must say, I'm having some troubles understanding it all. For example, in JSCIP, there are methods defined in SCIPJNIJNI like ObjMessagehdlr_director_connect that don't have a counterpart in scip. Where is that method implemented and what do they do? How can I in general find out what's going on here for things like this?

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