-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
tweak GC in OCaml bindings #5600
tweak GC in OCaml bindings #5600
Conversation
this forces the GC to collect garbage when a few _large_ objects (solver, etc.) are dead. The current code would let arbitrarily many such objects die and not trigger a GC (which would have to come from OCaml code instead)
This actually requires OCaml >= 4.08 to benefit from the new allocation function. |
Conceptually this seems like a good idea, but I'd add some way for applications to tweak those numbers without making changes to the API code. I'm also slightly concerned that this breaks compatibility with older versions of OCaml, which may be a problem for some existing projects. Minor: Why the change to Ubuntu 20? Does this hint at the fact that it won't work on Ubuntu 18 anymore? Also, I don't know what the guarantees of |
c5a8168
to
13589d6
Compare
@wintersteiger the Ubuntu 20.04 is just because it seems to use the system OCaml, which is 4.05 on Ubuntu 18.04 if I read the logs correctly. I agree it's unfortunate to require a more recent OCaml, but at the same time the most recent version is 4.13 already. This change is important to us because we want to move to 4.12 from 4.08 and the default GC behavior on 4.12 makes Z3 bindings a giant memory leak. 4.08 is a very stable version which brought a lot of new features people have come to depend on, so I think it's fine to establish it as a lower bound if it means people using more recent versions of OCaml can use Z3 at all. The finalizer seemed useful in local tests to keep RAM low. The interplay between OCaml finalizers (beeing called in a arbitrary order) and internal Z3 cleaning with refcountings is highly non trivial, so I'm not sure what's up. This ensures that the deletion code is run at least once at the moment the corresponding object is collected. |
If this works with you, very good. For early projects such as Pex, we got much better performance by not relying on the GC. |
Ah well, I was still working on fine tuning it, I'll probably open a second PR. Sadly it's difficult in OCaml to perform manual memory management so we're stuck with the GC. Unless there is a way we can modify the bindings to make this easier. I can imagine, for example, having a level of indirection internally, where there's a Another way would be to have an explicit notion of "region" where the context and solver and expressions would live, so we can deallocate them all at once. |
Just open another PR. The bare bones C API has it that expressions are pointers without pointers to contexts. The "region" notion is already there in one way: you can allocate a context in a mode where expression lifetimes come with the context. |
I will!
In that case, what I can use to refer to an expression through a context? Is there an integer key or something like that? That would be optimal for me. |
at Imandra we've had issues with recent versions of OCaml, where Z3 objects wouldn't be collected and would accumulate in RAM, eventually taking multiple GBs. There's some related issues for .NET I believe. This patch uses a different version of custom blocks (OCaml heap values that wrap foreign objects, such as a Z3 solver, expr, or context) with more explicit resource limits. I've hand picked limits that seem reasonable but it's subject to discussion. Pinging @ivg if he's interested.