Skip to content

Excessively large number of StringBuilder objects allocated in FormReader for big input data #2722

Closed
@aspnet-hello

Description

@aspnet-hello

From @yuwaMSFT on Friday, March 11, 2016 10:54:07 AM

In one stress run on Linux we hit OOM. During investigation, we saw excessive StringBuilder objects allocated in FormReader. The implementation will keep reading the stream until reaching a separator. In the test, we were posting faked large data ( > 16MB), which could cause the allocation of 2000 StringBuilder objects (8K chunk for each). If keep them all in memory we could only support very small number of clients. We probably can either reject big form or save data to temp cache file.

_### _OS Thread Id: 0xf462 (1)
        Child SP               IP Call Site
00007F27E6A441F0 00007F2862257CC9 [PrestubMethodFrame: 00007f27e6a441f0] System.Threading.Tasks.AwaitTaskContinuation.ThrowAsyncIfNecessary(System.Exception)
00007F27E6A448D0 00007F27E877FD9A System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A46688 00007F286185E1CD [HelperMethodFrame: 00007f27e6a46688]
00007F27E6A46D40 00007F27E7DF7792 System.Text.StringBuilder.ExpandByABlock(Int32)
00007F27E6A46D80 00007F27E82BB29E System.Text.StringBuilder.Append(Char, Int32)
00007F27E6A46DB0 00007F27E7BF044B System.Text.StringBuilder.Append(Char)
00007F27E6A46DD0 00007F27E97AD3F9 Microsoft.AspNetCore.WebUtilities.FormReader+<ReadWordAsync>d__10.MoveNext()
00007F27E6A46E10 00007F27E7DFCB9A System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00007F27E6A46E60 00007F27E877FF42 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run()
00007F27E6A46EA0 00007F27E877FD65 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A46ED0 00007F27E82B42D1 System.Threading.Tasks.Task.FinishContinuations()
00007F27E6A46F50 00007F27E878018F System.Threading.Tasks.Task`1[[System.Threading.Tasks.VoidTaskResult, mscorlib]].TrySetResult(System.Threading.Tasks.VoidTaskResult)
00007F27E6A46F70 00007F27E87800AE System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Threading.Tasks.VoidTaskResult, mscorlib]].SetResult(System.Threading.Tasks.VoidTaskResult)
00007F27E6A46FB0 00007F27E82C7D09 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Threading.Tasks.VoidTaskResult, mscorlib]].SetResult(System.Threading.Tasks.Task`1<System.Threading.Tasks.VoidTaskResult>)
00007F27E6A46FD0 00007F27E97AD7C6 Microsoft.AspNetCore.WebUtilities.FormReader+<BufferAsync>d__13.MoveNext()
00007F27E6A47000 00007F27E7DFCB9A System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00007F27E6A47050 00007F27E877FF42 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run()
00007F27E6A47090 00007F27E877FD65 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A470C0 00007F27E82B42D1 System.Threading.Tasks.Task.FinishContinuations()
00007F27E6A47140 00007F27E82B6E3C System.Threading.Tasks.Task`1[[System.Int32, mscorlib]].TrySetResult(Int32)
00007F27E6A47160 00007F27E877DAA6 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].SetResult(Int32)
00007F27E6A47190 00007F27E877CF35 System.IO.StreamReader+<ReadAsyncInternal>d__69.MoveNext()
00007F27E6A47230 00007F27E7DFCB9A System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00007F27E6A47280 00007F27E877FF42 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run()
00007F27E6A472C0 00007F27E877FD65 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A472F0 00007F27E82B42D1 System.Threading.Tasks.Task.FinishContinuations()
00007F27E6A47370 00007F27E82B6E3C System.Threading.Tasks.Task`1[[System.Int32, mscorlib]].TrySetResult(Int32)
00007F27E6A47390 00007F27E877DAA6 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].SetResult(Int32)
00007F27E6A473C0 00007F27E877D724 System.IO.StreamReader+<ReadBufferAsync>d__102.MoveNext()
00007F27E6A47450 00007F27E7DFCB9A System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00007F27E6A474A0 00007F27E877FF42 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run()
00007F27E6A474E0 00007F27E877FD65 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A47510 00007F27E82B42D1 System.Threading.Tasks.Task.FinishContinuations()
00007F27E6A47590 00007F27E82B6E3C System.Threading.Tasks.Task`1[[System.Int32, mscorlib]].TrySetResult(Int32)
00007F27E6A475B0 00007F27E877DAA6 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].SetResult(Int32)
00007F27E6A475E0 00007F27E97ADF19 Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream+<ReadAsync>d__24.MoveNext()
00007F27E6A47650 00007F27E7DFCB9A System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00007F27E6A476A0 00007F27E877FF42 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run()
00007F27E6A476E0 00007F27E877FD65 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
00007F27E6A47710 00007F27E82B42D1 System.Threading.Tasks.Task.FinishContinuations()
00007F27E6A47790 00007F27E82B34A8 System.Threading.Tasks.Task.Finish(Boolean)
00007F27E6A477D0 00007F27E7DFE091 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)
00007F27E6A47890 00007F27E7DFD873 System.Threading.Tasks.Task.ExecuteEntry(Boolean)
00007F27E6A478B0 00007F27E7E0F215 System.Threading.ThreadPoolWorkQueue.Dispatch()
00007F27E6A47C40 00007F286186EFA7 [DebuggerU2MCatchHandlerFrame: 00007f27e6a47c40]


(lldb) sos DumpObj 00007f27c361e368
Name:        System.Text.StringBuilder
MethodTable: 00007f27e7c4e480
EEClass:     00007f27e7c3d1b8
Size:        48(0x30) bytes
File:        /mnt/test/StarterMvc/bin/debug/dnxcore50/ubuntu.14.04-x64/mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007f27e7c29a08  4001616        8        System.Char[]  0 instance 00007f27cb23b8c0 m_ChunkChars
00007f27e7c4e480  4001617       10 ...ext.StringBuilder  0 instance 00007f27cb23f7c0 m_ChunkPrevious
00007f27e7c216a0  4001618       18         System.Int32  1 instance                0 m_ChunkLength
00007f27e7c216a0  4001619       1c         System.Int32  1 instance          4928192 m_ChunkOffset
00007f27e7c216a0  400161a       20         System.Int32  1 instance       2147483647 m_MaxCapacity_
_

Totally we had more than 10000 StringBuilder objects. 
_Statistics:
              MT    Count    TotalSize Class Name
00007f27e7c4e480    10539       505872 System.Text.StringBuilder
_

Statistics:
              MT    Count    TotalSize Class Name
00007f27e7c29a08    10690    166336624 System.Char[]

Copied from original issue: aspnet/HttpAbstractions#583

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stressarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-http-abstractions

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions