I am using the Java bindings for the CP-SAT model in OR-Tools. My application creates a big model but only holds a few refernces to some Int- and BoolVars. I realized that after the creation of the model (even before I call of CpSolver#solve). The Java Heap allocates multiple gigabytes just for the model.
I made a heap dump and found following entries:
long [] (mostly part of IntegerVariableProto$Builder, > 13,000,000 inst.) => 1,433 MB
com.google.ortools.sat.ConstraintProto$Builder (> 8,000,000 instances) => 1,194 MB
com.google.protobuf.SingleFieldBuilderV3 (> 21,000,000 instances) => 682 MB
com.google.protobuf.GeneratedMessageV3$1 (> 21,000,000 instances) => 511 MB
com.google.protobuf.IntArrayList (> 13,000,000 instances) => 445 MB
com.google.protobuf.LongArrayList (> 13,000,000 instances) => 433 MB
...
I understand, that a big model needs some memory. But after I had a look in the Java bindings code, it seems to me that theses objects are only used by protobuf to build a message to send the information to the native backend.
My question is:
Is there any way to use the Java API, without keeping these objects in memory (e.g. by incrementally flushing the model) and still having a reference to CpModel and some variables?
And how would it behave when I use C++ instead? I am confused here because
- I found an answer in the google group, it says that in C++ the model does not need to be serialized (https://groups.google.com/g/or-tools-discuss/c/5-6OthD5JQo/m/ZzeeXD34AAAJ)
- I had then a look in the repository (https://github.com/google/or-tools/tree/stable/ortools/sat) and saw that protobuf seems to be used there.
I tried it with OR-Tools version 9.3 and 9.7.
Thank you very much.
Currently the java wrapper is quite light. An intVar uses 2 pointers and one int32. Not much to gain here, and not much that can be deleted.
When solving, it will serialize the model to string, cross the C++/Java layer, rebuild the proto in C++, then solve using the C++ code.
Doing it in C++ will remove one copy and one serialization.
You have a bigger issue IMO with solve. Last time I checked, solving a 12M variables problems with a healthy number of workers took more than 256GB of RAM.
So it would be better to decompose the model, try to solve it sequentially, try to reduce its size. This would be time better spent than optimizing the intermediate layers.