If you have used both static methods and objects before then I am suprised that you do not see why people use objects so frequently. Objects make it easier to understand and also maintain code. Imagine if you wanted to store some data about a person and decided that you would only make use of static methods. You would have to have some way of coordinating the use of the methods so you know which name, age, address etc. belongs to which 'person'. This would likely result in very messy code that would quickly become difficult to maintain.

Objects provide the opportunity to group data and functionality so that code is easier to understand and use. Storing a collection of person objects is much more straight-forward than creating lots of static functions that attempt to group related data for the same purpose.

Another big reason is static methods occupy memory and so do C# object you might argue. But the memory occupied by C# objects (if no longer needed in your program) can be freed, and can be used by other programs.

If you are building server applications using pluggable modules (where you can just copy a newer assembly to replace an older one), then static objects are a problem because they are kept in memory (like ddanbe mentioned above). Then although the new assembly is in place, still the old code will be executed.

As for your question about heap memory, this post should help clarify how memory is allocated and used. It is written from a C/C++ perspective, however, so there is more to be added about it.

The first thing you need to know is that objects in C# are always in dynamically allocated memory. This makes it possible to add or remove objects freely, without having to worry about the space involved. But what happens when you run out of memory? Well, I'm going to get to that in a bit, but there are a few things to explain before I get to that.

The next thing is that there is a difference between a variable and an object. In C# (and many modern languages), a variable of an object type is not an object itself, but rather a reference to an object. This is in contrast to a variable of one of the primitive types (int, char, float, etc.), or of a struct type, where the value of the variable is the actual value being worked on. The value of a object type variable is a reference to where the object is in dynamic memory. A variable can itself be part of an object, or be part of a class; the former are called instance variables, while the latter are static variables or class variables. When you invoke the constructor of a class, you are actually allocating memory for the new object, after which the c'tor itself is run to set the values of the instance variables.

The next thing to understand is that static variables in C# is stored in what I referred to as global memory. Now, in this case, 'global' doesn't refer to the visibility of the variables; in C#, there are no global variables in that sense. In this case, global or static memory refers to memory that is allocated when the process is launched, and does not increase or decrease during the process' lifetime (I use the term process specifically to make it clear that we're talking about a particular invocation of the program; you can have two independent copies of a given program running in separate processes, each with it's own global memory). The static variables of a class are themselves in static memory; however, the values they hold may refer to objects in dynamic memory.

The next thing is regarding memory re-use. If you read that article, you see a comment about garbage collection, and the mention that it "isn't relevant" to C and C++. Well, in C#, garbage collection is very relevant. Unlike those two older languages, C# uses automatic memory reclamation, better known as garbage collection. What this means is that the system - the Common Language Runtime, in this case - keeps track of all of the internal pointers that make up the references, and periodically checks to see which objects no longer have any references pointing to them. Any object that has no references to it is freed, so that the memory can be reused. The actual details of garbage collection are a bit tricky, but the important thing to know is that objects in C# do not need to be explicitly deleted in order to free up memory.

I don't know how much this clarifies matters, as it is only tangentially related to your original question, but it may give you some of the necessary background to understand the answers.