-
Notifications
You must be signed in to change notification settings - Fork 7
Improve heap profile memory usage by lazily loading js objects #260
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
base: main
Are you sure you want to change the base?
Conversation
Overall package sizeSelf size: 1.91 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | source-map | 0.7.6 | 185.63 kB | 185.63 kB | | pprof-format | 2.2.1 | 163.06 kB | 163.06 kB | | p-limit | 3.1.0 | 7.75 kB | 13.78 kB | | delay | 5.0.0 | 11.17 kB | 11.17 kB | | node-gyp-build | 3.9.0 | 8.81 kB | 8.81 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-02-11 13:26:10 Comparing candidate commit fbcdce8 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 92 metrics, 28 unstable metrics. |
|
@codex review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d2982ce329
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Some thoughts:
|
| }; | ||
| } // namespace | ||
|
|
||
| std::shared_ptr<Node> TranslateAllocationProfileToCpp( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TranslateAllocationProfileToCpp and TranslateAllocationProfileToExternal are ~similar. While templating could reduce duplication, the different string assignment mechanisms would add complexity. Keeping both functions for clarity
|
|
||
| export interface AllocationProfileNode extends ProfileNode { | ||
| allocations: Allocation[]; | ||
| children: AllocationProfileNode[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing children type bug
7e1921f to
b0caf9a
Compare
|
Currently we have this processing flow for a heap profile:
IIUC the proposed change should decrease the JS memory used during the second step but at the expense of creating a copy of the entire C++ node tree. It would be nice to have benchmark / test cases that exhibits the behaviour that need fixing and measure the improvement. |
|
I added a benchmark for the second step that:
Results I got from Local and CI across platforms:
|
What does this PR do?:
Introduces a new lazy heap profiling API
profileV2that reduces memory usage during heap profile serialization. Instead of materializing the entire V8 allocation profile as JS object upfront, the new API traverses the profile root tree on-demandMotivation:
When collecting heap profiles, the current
profile()API callsGetAllocationProfile()to get the profile data, then recursively translate the entire profile tree into JS objects, this creates a full JS objects tree in heap memory which can be significant for large apps.The new
profileV2()API introduces a lazy traversal pattern, getting JS object is done on-demand using getters to get children, name, scriptName and others. On the TS side, we only request for current node JS object which allow us to gradually build the tree and reduce memory usage at this operation.Additional Notes:
The current implementation copies the V8 allocation profile to C++ heap to keep it alive after GetAllocationProfile() returns. I think that this is necessary because profile object has limited lifetime (
HandleScope). While this still a copy it's lightweight compared to creating full JS object since we only store raw profile data (string, number).