The article/code snippet includes various points that should be given time for effective memory management. It does not given solutions but gives an inside into what options are there.
- Effective use of Caching.
The main reasons for caching are performance related. Memory in ASP.NET is still a very limited resource. Do not waste it by caching anything more than a couple of minutes unless it is very expensive to regenerate. Various types of caching are:
• Page Level Output Caching: : This keeps a copy of the HTML that was sent in response to a request in memory. Subsequent requests are then sent the cached output until the cache expires. Thus round way trips are saved to memory and response time improves.
• Fragment caching, User Control Output Caching: There are situation where caching the entire page is not feasible. Only certain parts of the page are customized for the user. In such scenarios, fragment caching is used. Menus and other layout elements, especially ones that are dynamically generated from a data source, should be cached with this technique.
- Type Sizing
Memory usage ultimately depends on the types defined and used by the assemblies in your program. Here the important point is what types to be used since, the bytes occupied by .NET data types is fixed. bool takes 1 byte, double 8, decimal 16, Int32 takes 2 byte, etc... So nothing much can be done about these. The concern is structures, references. The size of a reference type is the size of its fields rounded up to the next 4-byte boundary, plus 8 bytes of overhead. So a reference type will always occupy at least 12 bytes. A Structure size is computed as the sum of the sizes of its fields but is problematic if you need to store a reference to the type, since frequent boxing can memory and CPU cycles.
Once an application is up and running, memory utilization is affected by the number and size of objects the system requires. Object pooling reduces the number of allocations, and therefore the number of garbage collections, required by an application. Pooling is quite simple: an object is reused instead of allowing it to be reclaimed by the garbage collector. Objects are stored in some type of list or array called the pool, and handed out to the client on request. This is especially useful when an instance of an object is repeatedly used, or if the object has an expensive initialization aspect to its construction such that it's better to reuse an existing instance than to dispose of an existing one and to create a completely new one from scratch.
Let's consider a scenario in which object pooling would be useful. Consider a loop wherein you want to compare the values in the record with a static value.
The code might contain a loop that does something like this:
Employee record = GetNextRecord();
In this loop, a new employee Record is returned each time the loop is executed. The most obvious implementation of the GetNextRecord method would create a new object each time it is called, requiring the object to be allocated, initialized, eventually garbage collected, and finalized if the object has a finalizer. When using an object pool, the allocation, initialization, collection, and finalization only occur once, reducing both the memory usage and the processing time that is required.
In some situations, the code could be rewritten to take advantage of a Clear method on the type with code like this:
Employee record = new Employee ();
- Garbage Collection.
You should almost never call GC.Collect() manually. And by almost I mean once in a lifetime, not once per application, and certainly not once per function call. I occasionally call GC.Collect() for testing purposes just to see if memory has been released. Normally you would never call it. The GC is self-balancing and by calling GC.Collect() you are disrupting that balance.
- Managed Heap.
When you initialize a new process, the runtime .NET environment reserves a contiguous address space for the process. This reserved address space is called the managed heap. The managed heap maintains a pointer to the address where the next object in the heap will be allocated. Initially, this pointer is set to the managed heap's base address. All reference types are allocated on the managed heap. When an application creates the first reference type, memory is allocated for the type at the base address of the managed heap. When the application creates the next object, the garbage collector allocates memory for it in the address space immediately following the first object. As long as address space is available, the garbage collector continues to allocate space for new objects in this manner.
Allocating memory from the managed heap is faster than unmanaged memory allocation.
- Session handling.
ASP.NET provides various modes of session state storage. This can be changed by the programmer using the mode attribute of <sessionstate> tag in your web application’s Web.config file. Below is a sample of this tag:
< sessionState mode="InProc"
Attribute|| Option|| Description|
|mode|| Specifies where to store the session state.|
| Off|| Disables session state management.|
|InProc||Session state is stored locally in memory of ASP.NET worker process.|
|StateServer||Session state is stored outside ASP.NET worker process and is managed by Windows service. Location of this service is specified by stateConnectionString attribute.|
|SQLServer||Session state is stored outside ASP.NET worker process in SQL Server database. Location of this database is represented by sqlConnectionString attribute.|
We access Session data through a property named Session. This Session property is an object of HttpSessionState class in System.Web.SessionState namespace.