I need to execute a long-heavy process for a question out of the box. So I have divided the process in multiple subprocess. The question now, is how to release memory, before the execution of each window.
It's easier to explain with an example. Let's take a look to this pseudo-code.
1. Some earlier code to do other things
2. Do
3. Raise a Task
4. If raised-task > 1000
5. Wait all raised task to finish
6. Release Memory
7. End If
8. Wile Something not relevant
With that idea, I have developed the next method, which gets executed every time it's reached the thread limitation:
List<Task> LTask();
//It's not relevant, but this list is populate like
//var task = Task.Run(() => something());
//LTask.Add(task);
private void waitForAll()
{
//Break point 1
Task.WhenAll(LTasks).Wait();
LTasks.Clear();
LTasks = null;
GC.Collect();
GC.WaitForPendingFinalizers();
//Break point 2
LTasks = new List<Task>();
}
I expected memory gets constant (whit some variation) around some values. I mean:
Next time the limit is reached and this code is executed, if I take a snapshot again, the memory keeps increasing: 200, 300, ...
This is a capture of diagnosis tools. Odd snapshots are taken every time break point 1 is reached, and Even snapshots on break point 2.
Second question, this will continue increasing whit no limit until it throws an Out of memory Exception
?
Last question, any alternatives to solve the problem, and release the memory?
UPDATE 1: After some tests, and thanks to the comments, I have developed a test code, to dig into it. There has to be involved something else. Plase, take a look to the next piece of code. The memory continue increasing with no limit.
private List<Task> LTasks = new List<Task>();
private void manageThreadholdLimit()
{
waitForAll();
realeaseMemory();
}
private void waitForAll()
{
Task.WhenAll(LTasks).Wait();
LTasks.Clear();
LTasks = null;
}
private void realeaseMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
LTasks = new List<Task>();
}
public void Main(){
int i = 0;
while (true)
{
i++;
var task = Task.Run(() => Thread.Sleep(100));
LTasks.Add(task);
//Si hemos alcanzado el máximo de paralelismo, esperamos la conclusión
if (i % 1000 == 0) manageThreadholdLimit();
}
}
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
Full form of C is “COMPILE”. One thing which was missing in C language was further added to C++ that is 'the concept of CLASSES'. So ++ being the increment operator, C has an incremented version called as “C++”.
C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.
It is fast The programs that you write in C compile and execute much faster than those written in other languages. This is because it does not have garbage collection and other such additional processing overheads. Hence, the language is faster as compared to most other programming languages.
GC collection is slightly different in debug, see:(John Skeet knows all) So I would do allot of logging when running this in release mode to verify all behaviours.
Any solution will be very dependent on your actual code and if there are unmanaged resources being accessed.
That said I have had to deal with a problem like this before and I have "solved" it in 2 different ways before.
One solution
Have counters that are incremented in constructor and decremented in the finalizer in the class that does the actual work and wait for the counter to fall under a defined threshold and importantly run collect again for the finalized objects to be collected.
Be careful checking the total memory consumption before continuing otherwise you can end up with out of memory exception.
Now this will actually increase your memory consumption slightly. For more info see
Another solution
Have a loop waiting for the memory consumption to fall by using GC.GetTotalMemory() or even better performance counters and wait for it to come down.
This can end up not doing any work at all if your resources are not being collected.
It is not guaranteed that the GarbageCollector
will run immediately after you unreference the object. In fact, it probably won't. Even if you want to call it manually for testing purposes with GC.Collect()
you have no real guarantees it will run immediately. Also, there is a cost to calling GC often. RAM is there to be used (at least in newer machines with lots of RAM...). You have a problem if your memory goes up, and stays up after a longer while. This usually indicates that you have some other memory problem. Maybe you have a leak?
If we're talking about free solutions, you can use ProcessExplorer and CLR Profiler to look for potential memory problems. Here is an article on how to do that.
Things to look out for:
null
as soon as you can. You are done with the list? Set its value to null
.null
, the GC won't run until a method is exited.Also, Task.WhenAll()
apparently keeps the references to all its "child" tasks. If you manually call GC immediately after it in the same method, I think there is a chance it won't be able to touch that memory, as the method itself is still "referencing" it.
Here is a MSDN article about garbage collection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With