C
C#7d ago
Yuji

✅ Memory leak or What?

Whenever I call my controller in .net web app, my memory usage gets increased on each call and it never decreases what can be issue?? I will share my code Snippets bellow!
80 Replies
Yuji
YujiOP7d ago
This is function that fetched data from db
FusedQyou
FusedQyou7d ago
$paste
MODiX
MODiX7d ago
If your code is too long, you can post to https://paste.mod.gg/, save, and copy the link into chat for others to see your shared code!
Yuji
YujiOP7d ago
ok wait
FusedQyou
FusedQyou7d ago
This code doesn't have any issues as far as I see btw Doesn't the memory lower after a short while?
cap5lut
cap5lut7d ago
from the provide code u clean up everything u would have to clean up, so the code is actually fine
my memory usage gets increased on each call and it never decreases what can be issue??
how long is that "never" and what is the memory pressure? the GC is by default not doing much to release memory below 90% of system memory usage. did u check if there are still instances somewhere in the memory, or is it just process allocated memory which from the GC point of view is free?
Buddy
Buddy7d ago
If you can afford to dump some money into it, https://www.jetbrains.com/dotmemory/ is an amazing tool to find possible memory leaks
JetBrains
dotMemory: a Memory Profiler & Unit-Testing Framework for .NET by J...
dotMemory allows you to analyze memory usage in a variety of .NET applications
Yuji
YujiOP7d ago
BlazeBin - geaypfyajbrj
A tool for sharing your source code with the world!
Yuji
YujiOP7d ago
Like when i send req again and again and again memory keep increasing :/
cap5lut
cap5lut7d ago
how do u look at it that the memory usage is increasing? just the task manager?
Yuji
YujiOP7d ago
No vs diagonistic tool
Yuji
YujiOP7d ago
This is at start of application
No description
Yuji
YujiOP7d ago
This is after making call
No description
Buddy
Buddy7d ago
Take a snapshot
Buddy
Buddy7d ago
When it's that high
No description
Buddy
Buddy7d ago
Then you can see what is taking up memory
Yuji
YujiOP7d ago
I did that but it says something like this wait
Yuji
YujiOP7d ago
No description
Yuji
YujiOP7d ago
After app loads and when i make like 15+ req Now how i can know what is issue :/
Yuji
YujiOP7d ago
No description
FusedQyou
FusedQyou7d ago
Okay but 92MB is not much Does it never collect, even after a minute?
Yuji
YujiOP7d ago
Nope :[
Yuji
YujiOP7d ago
No description
Yuji
YujiOP7d ago
right now its this
FusedQyou
FusedQyou7d ago
How is your data context created? And/or created in the factory
Yuji
YujiOP7d ago
Wait i will add extra code in that link SErvice factory is scoped same for factory
Yuji
YujiOP7d ago
BlazeBin - erzyhdvpvmqw
A tool for sharing your source code with the world!
Yuji
YujiOP7d ago
Go to end did changes
cap5lut
cap5lut7d ago
as u can see from the screenshots, the GC isnt even collecting garbage yet. there is simply not enough memory pressure to make it work their ass off
Yuji
YujiOP7d ago
So i should not worry about it :/
cap5lut
cap5lut7d ago
nope
Yuji
YujiOP7d ago
So my code is really safe? Like there is not any issue
cap5lut
cap5lut7d ago
none at all
Yuji
YujiOP7d ago
ok that's great to hear :'] Btw how good that code is written i know its not that big or anything complex but still any review?
cap5lut
cap5lut7d ago
its basically memory the process allocated, that doesnt even mean that the memory is actually used, the yellow GC thing is the stop-the-world-to-free resources. which it doesnt do if there is enough memory left (dont do extra work if ya dont need to)
Yuji
YujiOP7d ago
Ok gotcha!
cap5lut
cap5lut7d ago
its good and clean, the only thing i find weird is that u use the db context factory instead of just letting DI inject the context
Yuji
YujiOP7d ago
Yesterday i was thinking about doing concurrency with it. Like here i am getting list of data from different tables so why not i use parallelization But at that time i didn't knew that there is limit for max connection of context to db
cap5lut
cap5lut7d ago
both the controller and the dbcontext are usually registered as scoped lifetime. for asp.net there is a scope for each request, thus if u would use normal constructor injection for the dbcontext u would have the same result the dbcontext doesnt reflect connections
Yuji
YujiOP7d ago
Wait what :/ ?
cap5lut
cap5lut7d ago
they represent a unit of work
Yuji
YujiOP7d ago
Wait so what represent connection .. I misunderstood things that means --
cap5lut
cap5lut7d ago
under the hood there is connection pooling going on. the dbcontext will get a connection from that pool, or if there is none, it will establish a connection. but the whole thing is "i have one task to do, and for that i do the tracking and alike" the connections are handled under the hood for ya, u dont have to care about them
Yuji
YujiOP7d ago
Wait i remember there is something like DbContextPool, that is for connection? Oh ok
cap5lut
cap5lut7d ago
thats simple instance pooling, not even connection pooling ;p
Yuji
YujiOP7d ago
So there is way to controll that connection and pooling, if yes can u share article if you have or topic name so i can learn it further
cap5lut
cap5lut7d ago
uhh the actual connection pooling depends on the database driver efcore is using under the hood (yes, not even efcore itself deals with that), ill try to find something, but i dont think i ever had a guide/tutorial/documentation on that there is a small section about connection pooling, but better read the whole article: https://learn.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-di%2Cexpression-api-with-constant#connection-pooling-considerations
Yuji
YujiOP7d ago
So another thing I want to ask is how to know there is real memory leak like here it was not memory leaks or anything like that, also gc was not collecting stuff I am confused here
cap5lut
cap5lut7d ago
memory leaks are had to detect in managed environments like c#/.net. basically if u have hard memory pressure (like more than 90% of the system's memory usage) and the process' memory keeps increasing thats a hint
Yuji
YujiOP7d ago
So in order to do memory leak test i need to cook my system at max T-T
cap5lut
cap5lut7d ago
yep
Yuji
YujiOP7d ago
Man that's sad So one more question in .net memory leak can happen from following things right? 1) Expanding static container and never relasing its content 2)Circular refrence
cap5lut
cap5lut7d ago
it can be easy if u have virtualization/containerization (is the latter the correct word?) just give the instance only 1gb or less and see how it reacts
Yuji
YujiOP7d ago
Ok i never heared about this will look into that What 💀 ?
cap5lut
cap5lut7d ago
if u think something has a memory leak u can also take memory snapshots before and after invoking the respective code a couple of times and then compare
Yuji
YujiOP7d ago
But see above snapshot i share how i can find something in such a massive app Any resource to learn this kinda thing or its trial and error
cap5lut
cap5lut7d ago
thats two screenshots of the same snapshot, there isnt much u can see there and yes, its mostly try and error
Yuji
YujiOP7d ago
T-T i accidently shared same thing so only 1
cap5lut
cap5lut7d ago
its just like race conditions, there is no easy way to detect these
Yuji
YujiOP7d ago
c++ is better atleast u know when you allocating somethin -_- But that language is also nightmarish to deal with
cap5lut
cap5lut7d ago
tho i dont know much about c++, but i wouldnt say that. especially since assignment operator overload is a thing. isnt something like
auto v1 = new std::vector<int>();
// fill v1
auto v2 = v1;
auto v1 = new std::vector<int>();
// fill v1
auto v2 = v1;
making a copy of v1 and its data and stores that reference in v2? ignore that the namespace and constructor might be wrong, i didnt touch c++ in the last 15 years 😂
Yuji
YujiOP7d ago
nope here v1 will be pointer v2 will be also pointer
cap5lut
cap5lut7d ago
there was a collection type that did a copy on assignment, im 100% sure of that well, do they point to the same backing data? (also arent these references instead of pointers?)
Yuji
YujiOP7d ago
auto v1 = std::vector<int>;
// fill v1
auto v2 = v1;
auto v1 = std::vector<int>;
// fill v1
auto v2 = v1;
If its this then it will copy
cap5lut
cap5lut7d ago
will it copy the reference/pointer or also the backing data?
Yuji
YujiOP7d ago
It will copy in above code
cap5lut
cap5lut7d ago
its not a question of if its copying, but what its copying 😂
Yuji
YujiOP7d ago
content of v1
cap5lut
cap5lut7d ago
so if i modify the first element of v1 afterwards, v2's first element would still be the old value? basically
v1[0}++;
v1[0] == v2[0]
v1[0}++;
v1[0] == v2[0]
would that yield true or false?
Yuji
YujiOP7d ago
-----------------------
new std::vector<int>()
-----------------------
Heap address is 1000

auto v1 = new std::vector<int>() // returns start addrees means 1000
auto v2 = v1 // Points to 1000

So in the end

-----------------------
new std::vector<int>()
-----------------------
Heap address is 1000

It is pointed by both v1 and v2

And if you modify in v1 it will reflect v2 because they pointing to same stuff
-----------------------
new std::vector<int>()
-----------------------
Heap address is 1000

auto v1 = new std::vector<int>() // returns start addrees means 1000
auto v2 = v1 // Points to 1000

So in the end

-----------------------
new std::vector<int>()
-----------------------
Heap address is 1000

It is pointed by both v1 and v2

And if you modify in v1 it will reflect v2 because they pointing to same stuff
cap5lut
cap5lut7d ago
kk then it was another collection type that had that weird quirk anyway i only brought that up to demonstrate that cpp can have sneaky allocations behind the scenes as well 😂
Yuji
YujiOP7d ago
-----------------------
std::vector<int>()
-----------------------
stack address is 1000 (metadata stored here)

std::vector<int> v1; // v1 is created on stack at address 1000

std::vector<int> v2 = v1; // Copy constructor is invoked
// A new vector is created with the same content as v1
// Stored at a different stack address (e.g., 2000)
// A new heap allocation is done for the elements

So in the end:

-----------------------
std::vector<int> (v1)
-----------------------
stack address is 1000
heap address (data) is 3000

-----------------------
std::vector<int> (v2)
-----------------------
stack address is 2000
heap address (data) is 4000 (copied from 3000)

And if you modify v1, it will not reflect in v2
-----------------------
std::vector<int>()
-----------------------
stack address is 1000 (metadata stored here)

std::vector<int> v1; // v1 is created on stack at address 1000

std::vector<int> v2 = v1; // Copy constructor is invoked
// A new vector is created with the same content as v1
// Stored at a different stack address (e.g., 2000)
// A new heap allocation is done for the elements

So in the end:

-----------------------
std::vector<int> (v1)
-----------------------
stack address is 1000
heap address (data) is 3000

-----------------------
std::vector<int> (v2)
-----------------------
stack address is 2000
heap address (data) is 4000 (copied from 3000)

And if you modify v1, it will not reflect in v2
cap5lut
cap5lut7d ago
oh so it is indeed the one, it just depends on how u create v1 in first place xD
Yuji
YujiOP7d ago
Without new So here metadata of vector will be in stack
cap5lut
cap5lut7d ago
who ever thought of that difference in behaviour is probably a worse drunkard than me 😂
Yuji
YujiOP7d ago
Anyways I will run that thing on docker and monitor in constraint resources if something happens I will notify in this thread if i can Thanks for time and effort everyone, espicially cap5slut Have a great evening/day :]
cap5lut
cap5lut7d ago
well from the provided code u clean up everything as expected, there is nothing left to do there ;p
Yuji
YujiOP7d ago
bye also how to close this i dont have permission :/
cap5lut
cap5lut7d ago
there is the /close slash command
Yuji
YujiOP7d ago
u dont have permssion iit says

Did you find this page helpful?