IIS Optimization and Performance Tuning is quite a broad topic, and your bottleneck(s) could be several places.
First, you can better determine what your bottlenecks are by using the Performance Monitor.
Based on what you find there, you can move on to trying the following IIS performance tuning options:
- Use IIS
Compression.
- Enable at least static caching, and enable dynamic caching if it makes sense to do so.
- Tune your Aspnet.config
files
and machine.config files and web.config connection
strings
for your application(s).
Checking your connection strings in web.config
By default, the max pool size for connection strings in a web.config file is 100, so try specifying something higher, like "Max Pool Size=200; Min Pool Size=10; Connect Timeout=45;"
.
Example:
<add name="SiteSqlServer" connectionString="Server=mydomain.com;Initial Catalog=myDB;User ID=DB;Password=myDB;Max Pool Size=100;Min Pool Size=10;Connect Timeout=45;" providerName="System.Data.SqlClient" />
Checking your settings in Aspnet.config
Location: C:\Windows\Microsoft.NET\Framework\v2.0.50727 and C:\Windows\Microsoft.NET\Framework64\v2.0.50727
Example:
<system.web>
<applicationPool maxConcurrentRequestsPerCPU="5000" <!-- Default is 12 -->
maxConcurrentThreadsPerCPU="0" <!-- Default is 0 -->
requestQueueLimit="5000" <!-- Default is 5000 -->/>
</system.web>
Checking your settings in machine.config
Location:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG and C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG
processModel
Example:
<processModel
enable="true"
requestQueueLimit="5000" <!-- Adjust if necessary. Default 5000 -->
restartQueueLimit="10" <!-- Adjust if necessary. Default 10 -->
memoryLimit="60" <!-- Adjust if necessary. Lower for memory leaks. -->
maxWorkerThreads="100" <!-- Default 20 -->
maxIoThreads="100" <!-- Default 20 -->
minWorkerThreads="40" <!-- Default 1 -->
minIoThreads="30" <!-- Default 1 -->
/>
connectionManagement
Example:
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" <!-- Default is 2 --> />
</connectionManagement>
</system.net>
The developers might be right. In the .Net world, garbage collection and freeing memory happens when needed. I.e. if, there's plenty of memory available to the application, it may consume more and more, until the operating system does not allow more allocation. You shouldn't worry about that, unless it really causes problems.
Of course, there may be memory leaks, if the application does not properly dispose unmanaged resources, like sockets, file handlers, etc. Look at the operating system objects (in task manager, you can enable handles and user objects columns) to see how they grow.
As you stated, Application or Session object misusing can also be a cause.
I'm wondering why you would have 48 application pools (worker processes). This is overkill, and you do not need that at all.
The GC manages memory per process, and 400MB per process is not that much at all. Reduce the number of app pools to the nr. of cores - 1, and then stress test the application. If then it grows too much, you may be concerned about memory leaks.
Based on your additional information, yes, in that case the history list will grow indefinitely. Static objects are created once per application domain, and live until the appdomain lives.
I do not advise you to arbitrary remove the static keyword, unless you know that you do not break some application logic. Investigate why that data is collected anyway, and what it is used for. The code has another problem as well - it's not thread safe, it's behavior is undefined when 2 requests came in at the same time, and decide to add data to that list.
Better move your question to stackoverflow.com, as it's a programming question, and not administrative one.
If you are not in control off that code, and really want to just solve your memory problem, you can set your apppools to recycle after X number of requests, or after they get more than Y amount of memory - but again, that's not a real solution.
Best Answer
There are a bunch of queues that might be involved; I think your description is incomplete.
IIS allows you to specify that particular parts of a site run in different Application Pools, each of which runs in a separate worker process.
Each App Pool has a kernel-mode request queue (defaults to 1000 requests) used to ensure that in the case of a recycled W3WP (worker process) that requests don't get lost, but this also becomes the practical maximum limit for outstanding requests at a given moment.
If this queue fills up, you get a 503.
App frameworks - like .Net or classic ASP - may also implement their own user-mode request queue which runs within the worker process. I don't believe it's possible to prioritize different requests within the framework (unless there's an ASP.Net feature that does this that I'm not familiar with).
If you have a limited number of threads in each process' thread pool, separating apps into (for example) static content and active content app pools can help keep basic work off the thread pool of a busy app process. (Likewise, adding more threads is (arguably) a reasonable approach to this).