-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
How much is my memory? #31641
Comments
I tested in mac and windows, and saw the same behavior - with minor differences w.r.t numbers (probably owing to the system configurations and implementation differences in memory management at glibc / kernel), but the pattern is same. I found references that confirm my theory: relevant excerpt:
|
with that, I would like to convert this into a (libuv?) feature request: use case: ability for applications to figure out its memory usage in a reasonable manner - one of:
with a preference on the former. /cc @nodejs/libuv |
I'm not sure what you're asking for here. What's a "malloc cache"?
How would you measure that? The approach in Gregg's article is... creative.... but not something that can be generalized across platforms, possibly not even architectures. |
@bnoordhuis -
I agree that it is complicated, and might need OS support to achieve that; and hence I realistically opted for the first one. |
Oh, you mean arena allocations. Libuv has no insight into libc's bookkeeping though. You could write an add-on that calls glibc's |
@bnoordhuis - ok, but Libuv has malloc wrappers that can potentially keep a track of active allocations? I am not saying the entire app's memory demand funnel through Libuv. My take is that given Node.js is a language runtime that abstracts many implementation details from the underlying system, one or more or all of In the absence of that, the closest what we get is |
It does, but those only track what libuv itself allocates, which isn't much compared to Node or V8. An LD_PRELOAD wrapper will let you track all malloc/realloc/posix_memalign/free calls, however. |
@bnoordhuis - unfortunately, the LD_PRELOAD approach does not help on the immediate issue (#23277) or the wider need (accurate metering in Cloud deployments) An in-built, callable API will be the best way, and for the long term. |
I'm not sure we can influence metering in cloud deployments. Even if we find a way to provide working set size instead of resident set size, cloud providers would probably still consider rss for metering since the memory allocated in rss can't be allocated for other processes. While I agree it would be awesome to have a better way to visualize actual memory usage, we should also be aware that introducing yet another metric can lead to more confusion.
There's no guarantee native modules will use it, which can also lead to further confusion (as wss will be imprecise). If a native module depends on a third-party library (not uncommon), the library will definitely not use this callable API. Have you looked into how other languages and runtimes deal with this? It's hard to believe we're the first runtime trying to incorporate a more precise memory reporting solution. |
@mmarchini: thanks for the views!
Sorry for the confusion. I meant here about an API to get the accurate memory usage, not an allocation wrapper. Agree that we can't enforce third party native code to invoke the wrappers, so we might need to override the allocators. openj9 shows memory layout of the program to this level of granularity: NULL ------------------------------------------------------------------------
0SECTION NATIVEMEMINFO subcomponent dump routine
NULL =================================
0MEMUSER
1MEMUSER JRE: 1,063,311,424 bytes / 5393 allocations
1MEMUSER |
2MEMUSER +--VM: 788,956,312 bytes / 4855 allocations
2MEMUSER | |
3MEMUSER | +--Classes: 3,509,464 bytes / 124 allocations
2MEMUSER | |
3MEMUSER | +--Memory Manager (GC): 551,046,224 bytes / 2346 allocations
3MEMUSER | | |
4MEMUSER | | +--Java Heap: 536,932,352 bytes / 1 allocation
3MEMUSER | | |
4MEMUSER | | +--Other: 14,113,872 bytes / 2345 allocations
2MEMUSER | |
3MEMUSER | +--Threads: 25,027,616 bytes / 681 allocations
3MEMUSER | | |
4MEMUSER | | +--Java Stack: 902,280 bytes / 73 allocations
3MEMUSER | | |
4MEMUSER | | +--Native Stack: 23,199,744 bytes / 74 allocations
3MEMUSER | | |
4MEMUSER | | +--Other: 925,592 bytes / 534 allocations
2MEMUSER | |
3MEMUSER | +--Trace: 687,920 bytes / 455 allocations
2MEMUSER | |
3MEMUSER | +--JVMTI: 17,784 bytes / 13 allocations
2MEMUSER | |
3MEMUSER | +--JNI: 31,800 bytes / 49 allocations
2MEMUSER | |
3MEMUSER | +--Port Library: 207,028,232 bytes / 67 allocations
3MEMUSER | | |
4MEMUSER | | +--Unused <32bit allocation regions: 207,018,312 bytes / 1 allocation
3MEMUSER | | |
4MEMUSER | | +--Other: 9,920 bytes / 66 allocations
2MEMUSER | |
3MEMUSER | +--Other: 1,607,272 bytes / 1120 allocations
1MEMUSER |
2MEMUSER +--JIT: 273,076,160 bytes / 184 allocations
2MEMUSER | |
3MEMUSER | +--JIT Code Cache: 268,435,456 bytes / 1 allocation
2MEMUSER | |
3MEMUSER | +--JIT Data Cache: 2,097,216 bytes / 1 allocation
2MEMUSER | |
3MEMUSER | +--Other: 2,543,488 bytes / 182 allocations
1MEMUSER |
2MEMUSER +--Class Libraries: 1,278,952 bytes / 354 allocations
2MEMUSER | |
3MEMUSER | +--Harmony Class Libraries: 2,000 bytes / 1 allocation
2MEMUSER | |
3MEMUSER | +--VM Class Libraries: 1,276,952 bytes / 353 allocations
3MEMUSER | | |
4MEMUSER | | +--sun.misc.Unsafe: 528 bytes / 6 allocations
4MEMUSER | | | |
5MEMUSER | | | +--Direct Byte Buffers: 528 bytes / 6 allocations
3MEMUSER | | |
4MEMUSER | | +--Other: 1,276,424 bytes / 347 allocations
NULL
NULL ------------------------------------------------------------------------ and I guess it wraps malloc to achieve that: (gdb) where
#0 0x00007ffff745bad0 in malloc () from /lib64/libc.so.6
#1 0x00007ffff79b4fc5 in JLI_MemAlloc ()
from /opt/ibm/java-x86_64-80/jre/bin/../lib/amd64/jli/libjli.so
#2 0x00007ffff79b26ed in JLI_Launch () from /opt/ibm/java-x86_64-80/jre/bin/../lib/amd64/jli/libjli.so
#3 0x000000000040065a in main () |
@gireeshpunathil Node.js could provide allocation wrappers to libuv, but V8 (which most likely performs more native-heap allocations than libuv in a typical Node.js scenario) and Node.js itself use |
@addaleax in the report above I think only this section
is memory that would be reported in a heap snapshot. The rest is off-heap memory. Having said that it might not change your point that a lot of the memory is being allocated by V8 versus Node.js. Information on the Node.js allocations might be interesting anyway but would only be a subset of the overall. |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
thinking further on this, while this is reported by many users as seen from the linked issues, I don't see a practical way to implement this cross-platform. Let us may be keep it open for the next one month to see if any one has got ideas, or else let it close through the default bot action! |
( @gireeshpunathil note your comment opted-out of the bot behavior :) (I agree with what you wrote btw)) |
that is fine, I will keep an eye on this for a while to see any ideas on implementation, or else manual close |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment. For more information on how the project manages feature requests, please consult the feature request management document. |
This is opened for 3 reasons:
$ cat foo.cc
A linux (RHEL 8) observation:
The static memory usage (without the callocs) of this code is 12 MB
top output after the program runs and sleeps for enough time:
top output after the system is heavily
loaded
:pmap
shows 85 MB is still mapped into the process, matching withtop
.Observations:
rss
stays high (~ virtual memory) for ever, if there is no load in the systemProblems / questions:
rss
is a function of not only on the program's activity with memory, but also to other parts of the system.virtual memory
on the other hand was apparently the sum of allocations (malloc/calloc/mmap...) in the program, but looks like it is not, and depends on the glibc's memory management implementations and its discretion as to when to retain and when to release chunks back to OS, and as to what size of chunks qualify for removal, and may be also depend on the memory usage hueristics as well! When I used 4K chunks for calloc/free, I got different results.In Cloud workloads this has implications. A user would want to minimize memory tagged against their process and would do everything in their application to achieve that, but due the dependency on the system load and allocation caching behavior, this would not translate well?
memory leak definition becomes loose and detection becomes less comprehensive. Plurality of tools profiling the app from different angles would bring-in mutually contradicting results? For example: in a batch process, a code that genuinely leaks an MB versus an MB that is cached in malloc arenas - what is the difference from outside, and why should I worry more about the former and not worry about the later?
I read about wss (working set size) - that is a true measure of how much memory the program is actively engaged in. The idea looks like tracking paging-in; as that would be a true reflection of the program's needs. I don't find an API for this, nor a platform-neutral way to obtain this. Even if we could, this has an issue - the value is transient, as it depends on the history of usage, not the current state?
The text was updated successfully, but these errors were encountered: