Skip to content
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

Memory leak on Linux #89

Open
moebassist opened this issue Sep 10, 2021 · 8 comments
Open

Memory leak on Linux #89

moebassist opened this issue Sep 10, 2021 · 8 comments

Comments

@moebassist
Copy link

On Linux, there's a small memory leak.

Over a period of 25 minutes, 3.2mb was lost.

When the BACnet server is running but no clients are polling for real-time data (e.g. it's just sat there) - memory is stable. When clients poll, it rises.

This could be a tough one to crack.....any thoughts?

@gralin
Copy link
Member

gralin commented Sep 10, 2021

3.2MB isn't much, this could be easily caused by extra resources allocated by the CLR. But if you want to check to make sure, you could try to dump memory from two points in time (forcing GC before each) and check new resources which have been allocated. If you find some that shouldn't be there, check what is holding the mand why there weren't collected. I don't have experience in doing this on Linux but maybe if you attach VS debugger to app running in container/VM you could use the build in memory profiler. There is also dotMemory version for Linux. Tess Ferrandez also wrote a whole article about other options: https://www.tessferrandez.com/blog/2021/03/18/debugging-a-netcore-memory-issue-with-dotnet-dump.html

@moebassist
Copy link
Author

Over a 48 hour period my app has lost 27% memory. When the BACnet server is disabled, it sits happily at 19%.....forever.

Definitely a leak somewhere....I've started to trawl through it. The leak is small - I think this will be a nightmare to find since it could be in the BACnet stack, SharpPcap or mono. My hardware is an iMX6 with 1GB ram, so it's not really ideal for installing Rider and profiling with that.

@gralin
Copy link
Member

gralin commented Sep 13, 2021

Maybe do a similar test on different Linux machine with more resources? Or compare to a test without Mono by simply using .NET 5?

@scottpidzarko
Copy link

@moebassist did you eventually pinpoint the issue / confirm a leak?

Scott

@moebassist
Copy link
Author

Hi Scott,

I didn't.....I force a garbage collection and that reclaimed the memory....I know this isn't a great idea but I didn't have the time to review the entire library, and I don't have the CPU power/memory for a decent profiling.

It could be the recursive connection.BeginReceive(OnReceiveData... since tasks aren't disposed....this is a wild guess though!

I made a few changes to this library:

  • Removed dependency on SharpPCap.
  • Issues as per No response to WhoIs on Linux #88
  • Removed 'FindObject' and as much of the array creation/iteration as possible, replaced with dictionary e.g.:
//find in storage
var obj = FindObject(objectId);
if (obj == null)
    return ErrorCodes.UnknownObject;

//object found now find property
var p = FindProperty(objectId, propertyId);
if (p == null)
    return ErrorCodes.NotExist;

became:

if (!Objects.TryGetValue(objectId.instance, out clsBNObject obj)) return eBACnetErrorCodes.UnknownObject;
if (!obj.Properties.TryGetValue((int)propertyId, out clsBNProperty p)) return eBACnetErrorCodes.NotExist;

My application is dynamic...there could be a few hundred objects or a few thousand dependent upon config so I implemented dictionary use for simplicity, and it makes the storage class vary simple to use, since my dictionary keys are my BACnet object numbers.

One thing that was tricky - BACnet Multi States. are array based (1/2/3/4/5) whereas mine are enumerative, including gaps and negative numbers - e.g. an enumeration like this:

-1 : Error
0: Off
1 : On
4 : Failed

Is adjusted by adding the lowest absolute value+1:

1: Error
2: Off
3: On
4: (Not Used)
5: (Not Used)
6: Failed

Anthony.

@scottpidzarko
Copy link

Thanks Anthony for your prompt response, this will be really helpful. I am also dealing with a GB of RAM, in Mono, on a Linux kernel.

If it's running in production without major issues coming back to you about memory then that calms my fear of an actual leak down. Maybe when I finish my December deadline and things calm down for the holidays I'll spin up a virtual machine and try and replicate the memory climbing.

@moebassist
Copy link
Author

I have a 1 minute timer that performs all sorts of actions; I just banged a GC.Collect() in there. It’s running 24/7 without issues.

Ant.

@YarekTyshchenko
Copy link
Contributor

If GC can collect the memory then it doesn't sound like a leak. I'm sure the library could be made to do fewer allocations, but IMO as long as there's no leak, and it doesn't cause performance issue this isnt something to worry about

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants