Memory Leak - Activity objects not disposed in SmppSession.cs

Post Reply
ggsa
Posts: 6
Joined: Mon Oct 13, 2025 7:12 am

Memory Leak - Activity objects not disposed in SmppSession.cs

Post by ggsa »

Hi alt,

We discovered a memory leak in our production environment. Memory grows from ~2GB to 3.6GB over one week and never releases.

Environment:
- Inetlab.SMPP version: 2.9.35
- .NET 8
- Linux

Memory profiler shows DiagNode<ActivityEvent> objects accumulating: see image1.jpeg

Memory growth over time: see image2.jpeg

Root Cause Analysis:

Found issue in SmppSession.cs - Activity objects not disposed for throttled requests.

Line 960 - throttled path:
_ = SendResponseAndDelayedRequests(resp, null, activity, _cancellationTokenSource.Token);

Activity is created at line 933 but SendResponseAndDelayedRequests never disposes it. Only HandleReceivedRequest disposes activity at line 718, but throttled requests bypass this method.

Can you please review and confirm?

Thank you.
Attachments
image2.jpg
image2.jpg (219.09 KiB) Viewed 48 times
image1.jpeg
image1.jpeg (234.2 KiB) Viewed 48 times
Last edited by ggsa on Sat Nov 29, 2025 7:36 am, edited 1 time in total.
ggsa
Posts: 6
Joined: Mon Oct 13, 2025 7:12 am

Re: Memory Leak - Activity objects not disposed in SmppSession.cs

Post by ggsa »

Update: Possible root cause for our memory leak case - "Activity Theft" in SmppConnection

After deeper look into dotMemory, seems we found the cause.

Profiler Data:
- Activity objects: 49
- DiagNode: 5,158,820 (thousands events per Activity!)
- SmppConnection: 765
- SmppSession: 765

Retention path:
DiagNode<ActivityEvent> → Activity → ExecutionContext
→ AsyncStateMachineBox<SmppConnection+<Transferring>d__63>
→ _transferTask → SmppConnection

Potential bug:

SmppConnection constructor (line 182):
_transferTask = Transferring();

This captures current ExecutionContext. If Activity.Current has value at this moment (e.g., during connection recovery triggered while processing deliver_sm), the Activity might get "stolen" by Transferring() task.

Since Transferring() runs for entire connection lifetime, all subsequent PDU operations call Activity.Current?.AddEvent() (line 487) and add events to this captured Activity.

We have many bindings on this node. Some providers are unstable ("bad actors") and connection recovery is normal situation. When recovery happens during active deliver_sm/submit_sm processing, new SmppConnection captures the Activity from that context.

Result: 49 "contaminated" connections accumulated 5+ million events over one week.

Can you confirm this analysis?
Post Reply