Unmanaged memory leak in HttpResponse
I am developing a http handler running under IIS for streaming data from a server down to its clients. This works just fine. Until I open an oracle database connection before I stream the data. After I have opened the connection (and closed it again properly) all the data I am streaming will leak on the server, causing it to consume huge amounts of memory.
The .NET Memory profiler reports the following stack trace for the leaking memory allocations:
HeapAlloc()
[Managed to unmanaged transition]
UnsafeNativeMethods.BufferPoolGetBuffer(IntPtr)
HttpResponseUnmanagedBufferElement..ctor()
HttpWriter.CreateNewMemoryBufferElement()
HttpWriter.BufferData(byte[], int, int, bool)
HttpWriter.WriteFromStream(byte[], int, int)
HttpResponseStream.Write(byte[], int, int)
LeakingHttpHandler.ProcessRequest(HttpContext)
HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
HttpApplication.ExecuteStep(HttpApplication.IExecutionStep, bool&)
HttpApplication.ResumeSteps(Exception)
HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext, AsyncCallback, object)
HttpRuntime.ProcessRequestInternal(HttpWorkerRequest)
HttpRuntime.ProcessRequestNow(HttpWorkerRequest)
HttpRuntime.ProcessRequestNoDemand(HttpWorkerRequest)
ISAPIRuntime.ProcessRequest(IntPtr, int)
[Unmanaged to managed transition]Can anyone figure out how opening an oracle connection affects the unmanaged memory buffer pool in System.Web?I am running Windows Server 2003, IIS 6, .NET 2.0 and have tried both ODP.NET 10.2.0.1.0 and 10.2.0.2.20.
This is an example of a leaking http handler:
using System;
using System.Web;
using Oracle.DataAccess.Client;namespace MemoryLeak {
class LeakingHttpHandler : IHttpHandler {
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context) {
using (OracleConnection conn = new OracleConnection("...")) {
conn.Open();
}
context.Response.Buffer = false;
for (int i = 0; i < 100; i++) {
byte[] buffer = new byte[65536];
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
context.Response.End();
}
}
}
The http handler is set up with the following Web.config file:
<configuration>
<system.web>
<httpRuntime executionTimeout="1800" />
<httpHandlers>
<add verb="*" path="*.rem" type="MemoryLeak.LeakingHttpHandler, MemoryLeak" />
</httpHandlers>
</system.web>
</configuration>
After creating a virtual directory in IIS (called MemoryLeak) I just have to enter the correct url in Internet Explorer (http://localhost/memoryleak/foo.rem) a few times to make the memory consumption of w3wp.exe go sky high.If I remove conn.Open() from the code, the memory leak disappears.
If I set context.Response.Buffer = true (which I do not want to do), the memory leak disappears.
If I start a new thread, open the oracle connection in that new thread, and join with the thread, the memory leak disappears.
If I connect to a MSSQL database instead of Oracle, or connect to Oracle using the Microsoft provider in System.Data instead of ODP.NET, the memory leak disappears.
[7829 byte] By [
hmanner] at [2007-12-25]
I have run this errand through Microsoft developer support. This is the response from Microsoft:
"The OraOps10w module is calling the CoInitialize function on a thread that it didn't create, therefore this is a bug in Oracle code. Per KB http://support.microsoft.com/kb/911359/en-us, calling CoInitialize or CoUninitialize on a thread that is owned by the client process is not supported. Doing this is blocking our finalizer code from running and causing the memory leak to occur. You can see the offending call in the call stack below. Your options are to use the MS provider or contact Oracle for a fix. "
So now my situation is this:
- I can not use ODP.NET because of this bug
- I can not use the Microsoft provider because it does not support array inserts
Alternate link to KB article: http://www.kbalertz.com/911359/client.application.intermittently.receive.error.message.client.application.tries.create.component.aspx
The stack provided by Microsoft:
. 17 Id: f24.1ee8 Suspend: 1 Teb: 7ffa9000 Unfrozen
Start: kernel32!BaseThreadStartThunk (77e6b5f3)
Priority: 0 Priority class: 32 Affinity: 1
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\oracle\product\10.2.0\client_1\bin\OraOps10w.dll -
ChildEBP RetAddr Args to Child
01a5d674 04537e11 00000000 00000000 00000001 ole32!CoInitialize [d:\nt\com\ole32\com\class\compobj.cxx @ 1776]
WARNING: Stack unwind information not available. Following frames may be wrong.
01a5d68c 04566714 04530000 00000001 00000000 OraOps10w+0x7e11
01a5d6cc 045667bb 04530000 7c82257a 04530000 OraOps10w!OpsTSAAllocValCtxForToUTC+0x2604
01a5d6f4 7c8358fb 0456679e 04530000 00000001 OraOps10w!OpsTSAAllocValCtxForToUTC+0x26ab
01a5d7fc 7c835bcb 00000000 00000000 77e6a048 ntdll!LdrpRunInitializeRoutines+0x367 [d:\srvrtm\base\ntdll\ldrsnap.c @ 1183]
01a5da90 7c833ee5 00000000 03f71c58 01a5dd58 ntdll!LdrpLoadDll+0x3cd [d:\srvrtm\base\ntdll\ldrapi.c @ 524]
01a5dd0c 77e41bcc 03f71c58 01a5dd58 01a5dd38 ntdll!LdrLoadDll+0x198 [d:\srvrtm\base\ntdll\ldrapi.c @ 227]
01a5dd74 79e862c8 01a5de70 00000000 00000000 kernel32!LoadLibraryExW+0x1b2 [d:\nt\base\win32\client\module.c @ 507]
01a5dd98 79e8cc89 01a5de70 00000000 00000000 mscorwks!WszLoadLibraryEx+0x75 [f:\rtm\ndp\clr\src\utilcode\winfix.cpp @ 472]
01a5ddcc 79e8cbfd 01a5de70 00000000 00000000 mscorwks!CLRLoadLibraryExWorker+0x3d [f:\rtm\ndp\clr\src\vm\util.cpp @ 2817]
01a5de30 79e8fb18 01a5de70 00000000 00000000 mscorwks!CLRLoadLibraryEx+0x6b [f:\rtm\ndp\clr\src\vm\util.cpp @ 2837]
01a5de40 79e8f868 01a5de70 00000000 12463c09 mscorwks!`anonymous namespace'::LocalLoadLibraryHelper+0xf [f:\rtm\ndp\clr\src\vm\dllimport.cpp @ 2778]
01a5e560 79f1685d 03eb80e0 0000000d 00000001 mscorwks!NDirect::LoadLibraryModule+0x45f [f:\rtm\ndp\clr\src\vm\dllimport.cpp @ 3006]
01a5e6f0 79f167d0 03eb80e0 00000001 12463e35 mscorwks!NDirect::ComputeNDirectMLStub+0x75 [f:\rtm\ndp\clr\src\vm\dllimport.cpp @ 3237]
01a5e73c 79e8a871 01a5e75c 03eb80e0 12463e9d mscorwks!NDirect::GetNDirectMethodStub+0x50 [f:\rtm\ndp\clr\src\vm\dllimport.cpp @ 3313]
01a5e794 79e7bccf 03eb80e0 12463ee1 03eb80e0 mscorwks!MakeStubWorker+0x34 [f:\rtm\ndp\clr\src\vm\prestub.cpp @ 593]
01a5e7e8 79e7bb73 00000000 12463131 01a5ec5c mscorwks!MethodDesc::DoPrestub+0x1db [f:\rtm\ndp\clr\src\vm\prestub.cpp @ 1545]
01a5e838 01951efe 01a5e868 146aa5e0 00000000 mscorwks!PreStubWorker+0xed [f:\rtm\ndp\clr\src\vm\prestub.cpp @ 906]
01a5e8c0 79e88f63 7c82fb23 00000000 01a5e950 0x1951efe
01a5e8c4 7c82fb23 00000000 01a5e950 79e88ee4 mscorwks!CallDescrWorker+0x33 [f:\rtm\ndp\clr\src\vm\i386\asmhelpers.asm @ 936]
ThreadCount: 6
UnstartedThread: 0
BackgroundThread: 6
PendingThread: 0
DeadThread: 0
Hosted Runtime: no