You've described a classic case of “same code, different behavior” due to platform change—and that can be tricky to pin down. Let’s break it down and explore possibilities:
Alpine Linux is lightweight and uses musl libc, while RHEL 9 uses glibc and has more extensive background services.
The .NET Core runtime may behave differently due to dependencies compiled against glibc. Memory allocation strategies and garbage collection patterns can vary.
RHEL ships more diagnostics and background processes that can subtly increase memory footprint.
Your use of HttpContext
and Redirect()
looks correct and typically shouldn't hold memory.
But if the redirect endpoint is being hit very frequently, and responses are cached or buffered internally, memory can creep.
Possible culprit: server-side buffering, e.g., response streams not being disposed properly—especially if middlewares interact with HttpContext
.
Here are ways to isolate the issue:
ToolUse Casedotnet-countersTrack memory, GC, threadpool, HTTP counters in real-timedotnet-gcdumpSnapshot GC heap and analyze retained objectsdotnet-traceCapture traces to explore what’s allocating/proc/<pid>/smapsCheck actual memory usage per process, native vs managedK8s metrics (Prometheus + Grafana)Trend analysis over time per pod
Async Pitfalls: Though your endpoint is marked async
, you don’t await
anything. Consider dropping async
unless needed—it may affect thread use.
Middleware or Filters: Look at upstream middlewares or filters that might buffer HttpContext.Response
.
Logging: Excessive logging on redirect calls can gradually consume memory if not batched/flushed.
Connection Leaks: Ensure any downstream calls (not shown here) aren’t holding connections.
Try rolling back to Alpine with .NET 8.0 and compare memory diagnostics side by side with RHEL.
Consider building a minimal service that replicates your redirect pattern. Run identical traffic against both container bases and capture GC/memory snapshots.
Tune GC using environment variables—e.g., set DOTNET_GCHeapHardLimit
, DOTNET_GCHeapLimitPercent
.
This issue isn’t likely caused by one line of code—it’s the interaction of the runtime with the new OS environment. Want help analyzing a memory dump or building test scaffolds to narrow it down? I’d be glad to collaborate.