When executing an extended soak test on a high-throughput system, a linear rise in Resident Set Size (RSS) while Java heap metrics remain a perfect, stable sawtooth points to only one culprit: a native memory leak.
As a Lead QA Engineer, I recently faced this exact scenario. Our architecture was built for massive throughput: a customized Java test application simulated hundreds of concurrent users using our proprietary SDK to connect to the server. Simultaneously, a dedicated testing datasource blasted random real-time updates across a 500,000-row grid. Both streams fed into a performance-critical C server hosting a core Java Module via a JNI bridge. Tracking down native leaks across a JNI boundary usually requires days of manual pointer tracing or highly intrusive profiling tools that often crash heavy-load environments.
Instead, our team used Claude Code as an autonomous operations partner to implement Interval-Based Differential Core Dump Analysis, pinpointing a highly elusive race condition in our production codebase.
Our Grafana telemetry gave us a clear operational picture:
Initially, we fell straight into the common AI trap: Static Code Inspection. We spun up a replica test environment on a dedicated VM, gave Claude access to the live process, and let it passively scan the codebase for leaks.
Claude did identify several memory leaks in the code. However, our developer closely reviewed the findings and correctly caught that these were minor, edge-case leaks that rarely triggered. They were completely unrelated to the massive, aggressive memory creep we were actively seeing in our soak test environment.
Shortly after, Claude attempted intrusive runtime monitoring, which accidentally crashed the high-throughput server. This forced us to rethink our strategy entirely.
Our first instinct was the standard industry approach: running the C server under Valgrind. However, this approach failed immediately. Attaching Valgrind added a massive performance overhead that our high-throughput server could not sustain under the immense load of the 500,000-row grid simulation, causing the entire environment to stall and fail almost instantly.
If we couldn't hook into the process live or use heavy runtime instrumentation, we had to look at what was accumulating by comparing frozen states in time instead. We instructed Claude to interact with GDB and safely capture non-destructive core dump snapshots via gcore at 30-minute intervals without terminating the application.
Claude then parsed the data structures across both dumps, evaluated the memory deltas, and flagged a critical anomaly: the total count of a specific native C structure was growing linearly and never dropping. This structure functioned as a native cache, holding onto the calculated pivot results passed back from the Java module for our 500K-row grid. Each entry included a distinct subject name identifier designed to differentiate the cached pivot results—but the total number of these objects was now accumulating indefinitely.
To validate if this was a true leak or just delayed processing, we asked Claude to extract specific examples of these accumulating subject identifiers. Cross-referencing these names against our test client’s output confirmed that discard requests for these exact subjects had already been sent.
However, proving why they weren't destroying themselves was incredibly difficult. Our test environment was heavily loaded, generating hundreds of megabytes of logs every minute with aggressive rotation policies. Manual grepping was out of the question.
We instructed Claude to act as a log-sifting agent. We tasked it with finding a specific leaked subject identifier that had a documented discard receipt in the older logs but still maintained an active memory footprint in the latest core dump.
Claude successfully isolated a target subject. The log timeline revealed a lethal concurrency anomaly:
Subject_A.
Armed with the isolated subject identifier and the overlapping log timeline, we fed the core server codebase to Claude to execute a structural trace.
Because Claude had full contextual visibility of the codebase, it mapped the concurrent events to the underlying state machine, exposing a classic race condition:
While our team initially navigated this via an explicit log verification loop, this workflow highlights a repeatable paradigm we call Agentic Time-Slice Differential Analysis. Because terminal-bound AI agents operate natively alongside system utilities, this exact snapshot-and-compare pattern can be applied broadly across other software ecosystems to eliminate manual triage:
By instructing an agent to isolate growing objects via differential snapshot analysis, grep localized timelines out of volatile log streams, and cross-reference those timestamps against code repositories, we transform debugging from a game of intuition into an automated science.