Web applications have some vulnerabilities where over time their performance can significantly diminish. These vulnerabilities fall into two categories: memory leaks and deadlocks. Both can severely affect the performance of a Web application, even to the point where it comes to a grinding halt. And the .NET CLR offers some substantial help in these areas.
Wait a minute, though; .NET applications don't have memory leaks ”right? Yes, in theory that is correct. Unfortunately, though, some developer oversights can cause memory to leak. Take, for instance, an application variable in which user information is stored. What if information is added but never removed? What if the application variable holds more and more information as time goes by? The answer is that the memory the application consumes will go up, and the available free memory on the server will go down. And when available memory goes down, so does performance.
When the memory consumption gets so great that performance is poor, an application restart is necessary to get things back on track. ASP.NET applications can be configured so that they will restart when memory conditions reach a certain point. Actually, the Apache Web server has been doing this for years. It's great that Internet Information Server (IIS) enables ASP.NET applications to do this because all my Unix friends can't give me a hard time about this anymore. For years I've had to endure their jabs when I mention having to restart my Web server.
Setting a threshold for application restart couldn't be easier. All that's required is a simple addition to the Web.Config file as follows :
<processmodel memorylimit="75" />
This line causes the application to restart when available memory falls below 75%. You can set this percentage to anything that you feel is best for your application. Then, when the available memory falls below the threshold, a new instance of your application is spun up. This happens while the old instance is still satisfying requests. With both applications running, all new requests go to the new instance, and requests made to the old application are drained. Eventually, all requests to the old application are satisfied and no more requests are made to that application. At this point, the old application is released and all memory it was holding is released. This way, any new instance of an application will not be noticed by users.
There are many cases where an ASP.NET application must synchronize its use of resources. There might be a shared resource such as an Application variable that should be accessed by only a single thread, and simultaneous access could, for whatever reason, prove to be detrimental to the application's performance. In these cases, developers usually use the Lock() method to restrict the execution of a piece of code to a single thread and thereby ensure that only a single instance of code is accessing a resource. The Unlock() method then releases the locking mechanism so that other threads can execute the code.
There is an inherent performance hit for using these mechanisms. For starters, a certain amount of overhead is spent using Lock() and Unlock() . And what is probably even worse is that some threads have to wait until the lock is removed before continuing. In some cases, this significantly reduces an application's performance. But this can't always be avoided, and judicious use of Lock() and Unlock() is okay.
However, one of the problems with anything that holds up the execution of a thread, is that code which is interwoven with other code that uses locking mechanisms can sometimes result in a deadlock. This can happen when one thread locks a piece of code and then goes on to execute another piece of code. But another thread might be executing the second piece of code and have it locked, and then might need to execute the first piece of code, which is already locked. In cases such as this, each piece of code is waiting on the other piece of code to become unlocked. They can't proceed because each locked thread is waiting on the other. This a classic deadlock and brings a Web application to a grinding halt.
ASP.NET applications can be restarted in cases of deadlocks. A threshold can be set in the Web.Config file where the application restarts if enough requests build up in the queue. When a deadlock occurs, any request that gets hung up waiting for the locked code stays in the queue. For this reason, the request queue is a good indicator of a deadlock condition. Of course, you should be careful not to set the threshold so low that high traffic conditions will exceed the threshold. Reasonable values can be obtained using the performance monitor before the Web.Config file is edited.
The following entry restarts the application when there are 500 requests in the queue:
<processmodel requestqueuelimit="500" />
The same seamless method of starting a new instance of the application and gracefully moving requests from the old application to the new happens in the case of deadlock restarts just as it does for memory restarts.
The processmodel attributes can be seen in Table 21.1. They determine the behavior of the CLR with regards to your application.
Table 21.1. The processmodel Attributes
Waiting on poor memory conditions and deadlocks is one way to manage application restarts. You also can schedule restarts based on either elapsed time or requests. The following entry in the Web.Config restarts the application after 50 hours of operation:
<processmodel timeout="50" />
The following entry in the Web.Config restarts the application after 75,000 requests:
<processmodel requestlimit="75" />
It is important to note a few things regarding the application restarts. First, the ASP.NET files don't have to be recompiled at the next request. The compiled binaries are saved to disk and then reloaded in the new application. The second important point is that session state can be stored in the ASPState Windows NT service, or in SQL server. The following line in the Web.Config causes the session state to be stored in the ASPState service:
<configuration> <sessionstate inproc="false" server="localhost" /> </configuration>
If the service is not started, use the following command line to start it:
net start aspstate
Session state can be stored on a remote machine also. The following addition to the Web.Config file causes the session state to be stored in the ASPState service on a machine at 18.104.22.168:
<configuration> <sessionstate inproc="false" server="22.214.171.124" /> </configuration>