Troubleshoot Out of Memory issues (System.OutOfMemoryException) in ASP.NET
This article helps you troubleshoot Out of Memory errors in ASP.NET.
Original product version: ASP.NET
Original KB number: 2020006
Symptoms
One of the most common issues that we see in Microsoft Customer Support Services is OutOfMemoryException
scenarios. So we've put together a collection of resources to help troubleshooting and identifying the cause of memory issues.
Before we cover the details of troubleshooting an OutOfMemoryException
, it's important to understand what causes this problem. Contrary to what many developers believe, the amount of RAM that's installed doesn't impact the possibility of an OutOfMemoryException
. A 32-bit operating system can address 4 GB of virtual address space, whatever the amount of physical memory that is installed in the box. Out of that, 2 GB is reserved for the operating system (Kernel-mode memory) and 2 GB is allocated to user-mode processes. The 2 GB allocated for Kernel-mode memory is shared among all processes, but each process gets its own 2 GB of user-mode address space. It all assumes that you aren't running with the /3gb
switch enabled.
When an application needs to use memory, it reserves a chunk of the virtual address space and then commits memory from that chunk. It is exactly what the .NET Framework's garbage collector (GC) does when it needs memory to grow the managed heaps. When the GC needs a new segment for the small object heap (where objects smaller than 85 KB reside), it makes an allocation of 64 MB. When it needs a new segment for the large object heap, it makes an allocation of 16 MB. These large allocations must be satisfied from contiguous blocks of the 2 GB of address space that the process has to work with. If the operating system is unable to satisfy the GC's request for a contiguous block of memory, a System.OutOfMemoryException
(OOM) occurs.
Note
A 32-bit process running on a 64-bit operation system can address 4GB of user-mode memory, and a 64-bit process running on a 64-bit operation system can address 8TB of user-mode memory, so an OOM on a 64-bit operation system isn't likely. It is possible to experience an OOM in a 32-bit process running on a 64-bit operation system, but it usually doesn't occur until the process is using close to 3 GB of private bytes.
There are two reasons why you might see an OOM condition.
- Your process is using much memory (typically over 800 MB in a 32-bit environment.)
- The virtual address space is fragmented, reducing the likelihood that a large, contiguous allocation will succeed.
It's also possible to see an OOM condition because of a combination of 1 and 2. For more information, see Troubleshooting System.OutOfMemoryExceptions in ASP.NET.
When an OOM occurs, you may notice one or more of the following symptoms:
-
Your application crashes. For more information, see Who is this OutOfMemory guy and why does he make my process crash when I have plenty of memory left?.
-
Your application may experience high memory as indicated by Task Manager or Performance Monitor.
-
Requests may take a long time to process.
On Internet Information Services (IIS) 7, you can use Troubleshooting Failed Requests Using Tracing in IIS 7 to troubleshoot long-running requests.
-
Users may report an error message in the application because of the OOM.
When it comes to determining the cause for an OOM condition, you're actually working to determine the cause for either a high memory situation or a fragmented address space. While we can't document all of the possible causes of these situations, there are some common causes that we see regularly.
The following information outlines common causes of OOM conditions and the resolutions on resolving each of these causes.
String concatenation
Strings in a managed application (an application written by using the .NET Framework) are immutable. When a new value is assigned to a string, a copy is made of the existing string. And the new value is assigned to the new string. It doesn't typically cause any problems. But when a large number of strings are concatenated, it ends up causing many more string allocations than a developer might realize. And it can lead to memory growth and OOM conditions.
To avoid OOM because of string concatenation, make sure that you're using the StringBuilder
class. For more information, see How to improve string concatenation performance in Visual C#.
Fragmentation in the managed heap
The garbage collector (GC) in a managed application compacts the heaps to reduce the amount of fragmentation. However, it's possible to pin objects in a managed application. Pinned objects can't be moved during heap compaction. Doing so would change the address at which the object is located. If an application pins a large number of objects, and/or it pins objects for a long time, it can cause fragmentation in the managed heap. It can lead to the GC growing the managed heap more often and causing an OOM condition.
We've worked on minimizing OOM conditions because of pinning since the .NET Framework 1.0. Incremental improvements have been made in each version. However, there are still design patterns you can implement that will be beneficial if you have a need to pin objects.
Fragmentation in the Virtual Address (VA) space
Each process has a certain amount of memory allocated to it, and that memory represents the VA space for the process. If the VA space becomes fragmented, it increases the likelihood that the GC can't obtain a large block of contiguous memory to grow the managed heaps. And it can lead to an OOM condition.
Fragmentation in the VA space is often caused by one or more of the following scenarios:
-
Loading the same assemblies into multiple application domains.
If you need to use an assembly in more than one application running in the same application pool, strong-name the assembly and install it into the GAC. By doing that, you ensure that the assembly is only loaded into the process one time.
-
Running an application in production with the debug attribute of the
<compilation>
element set totrue
.- The debug attribute of the
<compilation>
element should befalse
when in production. - You can use the
<deploy retail="true" />
configuration to ensure that debug is always disabled in product. For more information, see deployment Element (ASP.NET Settings Schema).
- The debug attribute of the
-
Use of scripting within eXtensible Style sheet Language (XSL) transforms or creating
XmlSerializers
.In this case, dynamic assemblies caused by Extensible Style sheet Language Transformations (XSLT) scripting or
XmlSerializers
.
Return large sets of data
When using data from a database or other data source, it's important to limit the amount of data returned. For example, caching a query result that returns an entire database table to avoid the cost of retrieving parts of data from the database when needed isn't a good approach. Doing so can easily cause high memory and lead to an OOM condition. Allowing a user to start a similar query is another common way to create a high memory situation. For example, return all employees in a company or all customers in the state of Texas with a last name starting with the letter S.
Always limit the amount of data that can be returned from a database. Don't allow queries such as SELECT * FROM. . .
because you then have no control over how much data is displayed in your page.
It's equally important to ensure that you aren't displaying a large data result in UI elements, such as the GridView control. Besides the memory required for the returned data, you'll also consume large amounts of data in strings and in UI elements that are required to render the results. By implementing paging and validating input so that large sets of data aren't returned, you can avoid this problem.
Run in a production environment with tracing enabled
ASP.NET tracing is a powerful feature for troubleshooting applications. But it should never be left on in a production environment. ASP.NET tracing uses data structures such as DataTables
to store trace information, and over time, they can cause a high memory condition that can lead to OOM.
Tracing should be disabled in a production environment. You can do so by setting the enabled
attribute of the <trace>
element to false in your web.config file. Enabling retail deployment by using <deploy retail="true" />
also disables tracing in your applications.
Leak native resources
Many managed resources will also make use of native resources. Because the GC doesn't clean up native resources, a developer is responsible for implementing and calling the Dispose method to clean up native resources. If you're using a type that implements the IDisposable
interface, and you don't call the Dispose
method, you risk leaking native resources and causing an OOM condition.
These objects should implement the iDisposable
interface and you should call the Dispose
method on these objects when you no longer need them.
Recommended content
Quick things to check when you experience high memory levels in ASP.NET
This article describes the quick things to check when you experience high memory in Microsoft ASP.NET.
Original product version: ASP.NET
Original KB number: 893660
This article will start with some common issues, actions to remedy these issues, and a brief explanation of why these situations can cause problems.
ASP.NET Support Voice column
In the April 2005 Support Voice column, we inadvertently provided a link to the wrong file. Instead of linking to a download for the Web service, we linked to the XML file returned by the Web service. That link has been corrected. If you'd like to review the article with the correct file attached, see Dynamic page updates using XMLHTTP.
What's considered high memory
Obviously, this question depends on volume and activity of specific applications. In general, high memory is when your ASP.NET worker process (Aspnet_wp.exe) or Internet Information Services (IIS) worker process (W3wp.exe) memory is consistently increasing and isn't returning to a comfortable level.
In general terms, a comfortable level would be under 600 MB in the default 2-GB user memory address space. Once the memory level is higher than that comfortable level, we're doing less than we should be. This behavior may affect other applications that are running on the system.
The key is to understand some applications require more memory than others. If you're exceeding these limits, you may add more memory or add another server to your Web farm (or consider a Web farm). Profiling is also recommended in these cases. It can enable developers to create leaner applications. In this article, we're looking at a situation where you consistently see memory rise until the server stops performing.
Application set up for debugging
One reason for high memory that we see here in Support a lot is when you have debugging, tracing, or both enabled for your application. Enabling debugging and tracing is a necessity when you develop your application. By default, when you create your application in Visual Studio .NET, you'll see the following attribute set in your Web.config file:
<compilation
...
debug="true"
/>
or
<trace
enabled="true"
...
/>
Also, when you do a final build of your application, make sure that you do it in Release mode, not Debug mode. Once you're in production, debugging should no longer be necessary. It can really slow down your performance and eat up your memory. Setting this attribute means you change a few things about how you handle your application.
First, batch compile will be disabled, even if it's set in this compilation
element. It means that you create an assembly for every page in your application so that you can break into it. These assemblies can be scattered randomly across your memory space, making it more difficult to find the contiguous space to allocate memory.
Second, the executionTimeout
attribute (<httpRuntime> Element) is set to a high number, overriding the default of 90 seconds. It's fine when debugging, because you can't have the application time out while you patiently step through the code to find your blunders. However, it's a significant risk in production. It means that if you have a rogue request for whatever reason, it will hold on to a thread and continue any detrimental behavior for days rather than few minutes.
Finally, you'll be creating more files in your Temporary ASP.NET files folder. And the System.Diagnostics.DebuggableAttribute
(System.Diagnostics Namespace gets added to all generated code, which can cause performance degradation.
If you get nothing else from this article, I do hope you get this information. Leaving debugging enabled is bad. We see this behavior all too often, and it's so easy to change. Remember it can be set at the page level. Make sure all of your pages aren't setting it.
String concatenation
There are applications that build HTML output by using server-side code and by just building one large HTML string to send to the browser. It's fine, but if you're building the string by using +
and &
concatenation, you may not be aware of how many large strings you're building. For example:
string mystring = "<html>";
mystring = mystring + "<table><tr><td>";
mystring = mystring + "First Cell";
mystring = mystring + "</td></tr></table>";
mystring = mystring + "</html>";
This code seems harmless enough, but here's what you're storing in memory:
<html>
<html><table><tr><td>
<html><table><tr><td>First Cell
<html><table><tr><td>First Cell</td></tr></table>
<html><table><tr><td>First Cell</td></tr></table></html>
You may think that you're just storing the last line, but you're storing all of these lines. You can see how it could get out of hand, especially when you're building a large table, perhaps by looping through a large recordset. If it's what you're doing, use our System.Text.StringBuilder
class, so that you just store the one large string. See Use Visual C# to improve string concatenation performance
.NET Framework Service Pack 1 (SP1)
If you aren't running the .NET Framework SP1 yet, install this SP if you're experiencing memory issues. I won't go into great detail, but basically, with SP1 we're now allocating memory in a much more efficient manner. Basically, we're allocating 16 MB at a time for large objects rather than 64 MB at a time. We've all moved, and we all know that we can pack a lot more into a car or truck if we're using many small boxes rather than a few large boxes. It's the idea here.
Don't be afraid to recycle periodically
We recycle application pools in IIS every 29 hours by default. The Aspnet_wp.exe process will keep going until you end the task, restart IIS, or restart the computer. This behavior means that this process could be running for months. It's a good idea for some applications to just restart the worker process every couple of days or so, at a convenient time.
Questions to ask
The previous were all things that you can fix quickly. However, if you're experiencing memory issues, ask yourself these questions:
-
Am I using many large objects? More than 85,000 KB are stored in a large object heap.
-
Am I storing objects in Session state? These objects are going to stay in memory for much longer than if you use and dispose them.
-
Am I using the
Cache
object? When it's used wisely, it's a great benefit to performance. But when it's used unwisely, you wind up with much memory used that is never released. -
Am I returning
recordsets
too large for a Web application? No one wants to look at 1,000 records on a Web page. You should be designing your application so that you never get more than 50 to 100 records in one trip.
Debugging
I won't get into setting up WinDbg. But you can use the following commands to see what exactly is in your memory, if you wish to troubleshoot more complicated issues.
!eeheap -gc
This command will show you how much managed memory you have. If this value is high, there's something that your managed code is building.
!dumpheap -stat
This command will take quite a while to run, even hours if your memory is large. But this command will give you a list of all of your objects, how many of each type, and how much memory each is using. (For example, for the StringBuilder
class, you'll see many System.String
objects)
Once you've found an object taking much memory, dig further by using the following command:
!do <addr>
You can get the address of the object you're looking for in the dumpheap
command.
We'll be trying to incorporate more ways to use this diagnostic tool for specific situations in these columns. Let us know if we're doing a good job!
Memory and performance articles
Garbage Collector Basics and Performance Hints
Developing High-Performance ASP.NET Applications
ASP.NET Performance Monitoring, and When to Alert Administrators
Improving .NET Application Performance and Scalability
Recommended content
-
Troubleshooting native memory leak in an IIS 7.x Application Pool
Debug Diagnostics 1.2 Performance Monitor Debugging Tools for Windows This material is provided for informational purposes only. Microsoft makes no warrantie...
-
Performance issues when you call web services - ASP.NET
This article provides help to solve the performance issues that occur when you make calls to web services from an ASP.NET application.
-
gcServer Element - .NET Framework
Learn more about: element
-
Debug a memory leak tutorial
Learn how to debug a memory leak in .NET Core.
标签:ASP,re,Troubleshoot,Memory,large,application,memory,NET,your From: https://www.cnblogs.com/ioriwellings/p/17107160.html