-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Fix memory leak for Transaction Controller using parent samples #6386
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: master
Are you sure you want to change the base?
Conversation
|
memtest.jmx.zip
When doing the exact same with with parent=false, nothing is there, only the previousResult (which is good). After the fix, we have the same result, only previousResult is still in memory, but all transaction data is cleared after it is finished. |
|
@vlsi I've added an example script, added heap dump screenshot and improved the code. I only needed a workaround in the JMeterTest.java code or else I was getting serialization errors. Maybe you can take a look further, I think this is a major improvement when it comes to memory consumption. My current workaround is to disable parents for transactions to keep memory at ease |
|
@jgaalen , thanks for the reproducer. I've got 1G dump, and I'll take a look into it |
| .map(Serializable.class::cast) | ||
| .filter(o -> !o.getClass().getName().endsWith("_Stub")); | ||
| .filter(o -> !o.getClass().getName().endsWith("_Stub")) | ||
| .filter(o -> o.getClass().getName().startsWith("org.apache.jmeter.")); |
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.
Could you please clarify what is the reason to add this filter?
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.
Tests kept failing so ended up adding this line which fixed it
|
Status update on this ticket to be merged? This is a great improvement on memory when using the Transaction Controller with parent samples enabled. |
47cbb05 to
dc05215
Compare
… mode This commit provides a proof-of-concept fix for the memory leak issue identified in PR apache#6386, using a different and more effective approach. Problem: When Transaction Controller uses "Generate Parent Sample" mode, it accumulates SampleResult objects with large response data (body, headers, etc.) as sub-results. These remain in memory until thread completion, causing heap usage to grow from ~50MB to 150-200MB in long-running tests. Root Cause: Sub-results are added to TransactionSampler with full response data even though only metrics (timing, success/failure, byte counts) are needed for transaction aggregation after listeners have been notified. Solution: 1. Added SampleResult.clearHeavyDataForTransaction() method to clear response data, headers, and assertion details while preserving metrics 2. Modified JMeterThread to call this cleanup at two locations: - After listeners are notified but before adding to transaction (line 608) - When nested transactions complete (line 500) 3. Added configurable property transaction_controller.clear_subresult_data (default: true) to allow users to disable if needed Benefits: - Expected 50-70% reduction in heap usage for transaction-heavy tests - Backward compatible via configuration property - Safe: cleanup only after listeners have processed the data - No threading issues or test modifications required Files Modified: - SampleResult.java: Added clearHeavyDataForTransaction() method - JMeterThread.java: Added cleanup calls before adding sub-results - jmeter.properties: Added configuration property - TRANSACTION_CONTROLLER_MEMORY_FIX.md: Comprehensive documentation This approach differs from PR apache#6386 which attempted to replace TransactionSampler instances in TestCompiler.done(), which was ineffective as TransactionController already creates new instances per iteration. Related: PR apache#6386

Description
Follow issue in this issue
Basically, there's a memory leak, specifically when transactions are set as a parent. All the sub results maintains their data until the end of the thread, which can build up significantly, especially when there are large (uncompressed) responses
This PR fixes this, and improves the memory usage of JMeter by a lot, even without using transactions. Because we're cleaning all the SamplerResult data after it's sent to all the listeners. There is no reason to maintain the sampler data for that specific thread. It now clears all fields with large data and removes the parent reference, so GC can actually clear it.
Motivation and Context
JMeter is very memory intensive and by far the majority of the memory is used for processed samplers, just holding memory until the end of the thread run.
How Has This Been Tested?
I've done a lot of testing, made fixes and looks like it is working out well and preserving all the sampleresults/httpsamplerresults to all the listeners.
I've made a couple of scripts to test with a lot of transactions, with and without parent usage. Some synthetic scripts with a lot of 1MB json requests
Screenshots (if appropriate):
This is a graph of original 5.6.3 version, with 30 transactions, using parents, and a single 1MB.json file in it. Running 30 threads and 1 second think time between the transaction (meaning a thread runs 30 seconds + response times)
Then ran the exact same jmx against this fix:
Also ran the same tests without the usage of transaction as a parent:
5.6.3 baseline:

This fix:

Without the fix, we can see actual heap usage is hovering between 150MB and 200MB, with a max heap 420MB. With the fix, it is hovering between 50MB and 100MB with a max heap of 247MB. Also much more stable.
I've done some aggressive manual full GCs to see the real usage, and after the fix, the low end was significantly lower.
Here's a run against a realistic real website, 5 pages (transactions) with parent=true:
5.6.3 baseline:

After the fix:

Types of changes
It creates a deep copy of the sampler result and then forwards that to the listeners. After that we can safely remove all the values from the sampler.
It now only clears data after a root sampler is done, because if it's not on the root and generateParent is enabled, subresults keep building up.
Checklist: