-
Notifications
You must be signed in to change notification settings - Fork 195
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
GraalVM Node OutOfMemory Truffle's DynamicObjectBasic not released on GC #268
Comments
Hi @yacota thanks for sharing your insight and the extensive data you provided. Can you by any chance also provide the core of your code, i.e. where you create JavaScript and how you store them? Without any source code, my first guess would be you create lots of differently shaped larger objects (i.e., objects with different properties, of different types). We create "Shape" Objects for that in the background (think of that as a Class in Java). You either retain links to all those types somehow, or there is a bug in our strategy to garbage collect them once unsed. A similar problem we had seen before was when a JavaScript object was used like a map, with GUID values created and set as properties on those objects. That created a unique shape for each such GUID. @woess can you have a look and that and assess whether this is a problem on our side, or in @yacota 's code? Thanks, |
Hi, The execution path that I am testing is ALWAYS the same, the same html(600k) that it gets processed with jsdom @woess , as said before I can share the heapdump if needed Thanks |
Thanks for the bug report @jordillachmrf - couple of questions:
|
Hi @mikehearn ,
|
Sample project https://github.com/Marfeel/graalvmjs-issue |
Just taking a quick look, when are you expecting it to GC? If you get rid of the futures and just use The program runs a large loop that runs a bunch of tasks asynchronously, but with a 5 second delay between each iteration (and NodeJS/NodeJVM doesn't do parallelism so it is effectively synchronous). It uses the async version and adds all the returned futures i.e. object graphs to a Java list, then does a CompletableFuture.allOf to join all the futures. So by the time the loop is reaching the end there will be up to 1000 JS object graphs in memory. Additionally each loop runs I'd suggest tweaking the benchmark a bit first to see if letting the GC reclaim results after each iteration helps. |
Hi @mikehearn , thanks for taking a look at it.
|
I think the expensive object is the Try making Context cached as well and see what happens. |
Hi @mikehearn
All these tests and the related results make me think that each evaluation creates new objects that are finally linked to the engine and not properly GCed. For your information, these are the types of expressions I typically evaluate (basically, a function declaration and a function call): function eval() { function eval() { Kind regards, |
I am facing same problem@dariol83 , have you got any solution? , I cached the Engine and context
|
@nksaini83 when you say "context from cache", does that mean you don't ever |
@wirthi thanks for quick reply , for .close() i have to create context for every call , and it will give bad performance, that means we cannot cached the context . |
I wonder if you encapsulated your business logic in some functions. That would keep the number of global objects fixed (which is the number of the functions) so that GC could easily collect the orphan objects. I'm not sure how GraalJS handles this approach, but am sure V8 is awesome in it. |
Is that an assumption, or did you actually try that? Yes, creating a |
Yes i did that in starting , that is why we cached context. Today i clear Engine after X iteration and every thing work fine. I have also use Code Caching Across Multiple Contexts properly private final Engine sharedEngine = Engine.newBuilder().build(); public Context create() throws Exception{
@wirthi pls let us know if any thing wrong in above code or what we can do solve this problem ?. |
@wirthi Should we use this? |
Hi, no, unless you are on GraalVM 19. You should be on GraalVM 21.x., if not GraalVM 22.x. The comment was a workaround for GraalVM 19 specifically.
That sounds like a reasonable compromise. Note, however, that this way you might have user-observable exchange of data between contexts. So don't run multiple customers on that system. Only a fresh Context guarantees isolation of the global state of your application. In addition, you use a very insecure setup (HostAccess.ALL, allowAllAccess, allow access to all classes) - that does not sound resonable for an application in production - particularly not if you execute untrusted JavaScript code. Best, |
As per doc we can use same context for multiple threads. And we ensure only one thread access same context at given time. Thanks |
Hi, yes, that is possible. You need to make sure you correctly https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html#enter-- -- Christian |
That means it will resolve memory related problem? Narendra |
Hi @nksaini83 I don't know anything on the details of the memory-related problem on your side. My comment was that if you never close a Context, as you stated in your first comment, then you most certainly will have garbage piling up in the Context instance(s). Our suggested mode of operation is to use a fresh Context for each new query/customer/request/etc. If you prefer to cache Contexts, that might be ok, but of course, it can lead to data leak from one context to the other as I discussed above. We sometimes find and fix memory leaks. We are not aware of any open memory leak at the moment, given you use the latest version of GraalVM and use a fresh Context every time (or at least, re-create them frequently enough). To really help you with a specific problem: If you provide a runnable example of the problematic code that reproduces the issue, we are happy to look into it. Then we can run it on our machines and analyze the problem directly. Best, |
I tried both clearing context/Engine after X iteration in case of context nothing happened( memory not freed). |
I am using GraalVM's node to launch a Java application, the primary js is loading the Java application and both share a java.util.concurrent.LinkedBlockingDeque which is used to "send/share" tasks to execute from Java to the worker node thread.
The idea is somewhat similar to what is described in "Sharing Objects between workers" https://medium.com/graalvm/multi-threaded-java-javascript-language-interoperability-in-graalvm-2f19c1f9c37b
The js worker thread is using npm modules like jsdom, all of them are supported by GraalVM's npm
The peak performance is reached with a few request and the performance is even better than a "real" NodeJS application which does exactly the same, but the problem happens because a lot of DynamicObjectBasic are allocated, these can not be garbage collected and at the end an out of memory happens
The GraalVM version is 20.0
I've tested the application with 2 configurations
graal_diagnostics_26432.zip
With the default configuration I've analysed with Eclipse MAT the heapdump and it highlights the following
and
I can share the memory dump if you wish, just ping me and I'll share it through dropbox
During the execution one can see that the allocation of DynamicObjectBasic increases, but it hardly decrease although invoking JVM's GC explicitly
In t
In t+1
The memory usage trends more or less looks like this
And the heap histogram like this
I can try to create a simple project that will allow you to reproduce the problem if needed
The text was updated successfully, but these errors were encountered: