C# is very intelligent when it comes to managing its memory. Like Java and Python, it automatically manages memory; heap memory is managed automatically and stack data generally is, as well. For example, it will not allocate memory for an object or generic that is never used. On 32-bit systems, each program has 2GB of virtual address space; this is the space we manipulate–never the memory directly. Among other advantages, automatic memory management avoids problems such as dangling pointers and memory leaks
Garbage collection is done when the system has low physical memory or when the heap's allocated objects take up more than the allowed memory level. Automatic collection can also be done, but has almost no practical applications. C# has three "generations" that are used in garbage collection: 0 for short-lived data such as temporary variables, 1 (a buffer between short and long-lived data), and 2 for long-lived data such as static data used throughout the program.
I did Task 2 in C#, as well. I made a loop that called a function that uses up a certain amount of memory several times. Every so often, C# will automatically do garbage collection, making some calls take longer. We can see this with call 12, 16, 20, etc. I used the StopWatch object to count the elapsed seconds.