Investigating an OutOfMemoryException

time to read 4 min | 617 words

Originally posted at 1/5/2011

I finally got a reliable reproduction for a repeated error, but I have to say, just based on the initial impression, something very strange is going on.

image

The stack trace was a bit more interesting:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
  at System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
  at System.Text.StringBuilder.GetNewString(String currentString, Int32 requiredLength)
  at System.Text.StringBuilder.Append(String value)
  at System.Text.RegularExpressions.RegexReplacement.ReplacementImpl(StringBuilder sb, Match match)
  at System.Text.RegularExpressions.RegexReplacement.Replace(Regex regex, String input, Int32 count, Int32 startat)
  at System.Text.RegularExpressions.Regex.Replace(String input, String replacement, Int32 count, Int32 startat)
  at System.Text.RegularExpressions.Regex.Replace(String input, String replacement)
  at System.Text.RegularExpressions.Regex.Replace(String input, String pattern, String replacement)
  at HibernatingRhinos.Profiler.BackEnd.SqlStatementProcessor.ReplaceParametersWithValues(String statement, Boolean useComment) 

I put a breakpoint in the appropriate place, and discovered that the error occurred in:

  • A SQL Statement that was 190 kilobytes in size
  • It had 4,060 parameters

Now, let us look at the actual code:

private string ReplaceParametersWithValues(string statement, bool useComment)
{
  if (sqlStatement.Parameters == null)
    return statement;

  foreach (var parameter in sqlStatement.Parameters
            .Where(x => x != null && x.Name.Empty() == false)
            .OrderByDescending(x => x.Name.Length))
  {
    var patternNameSafeForRegex = Regex.Escape(parameter.Name);
    var pattern = patternNameSafeForRegex + @"(?![\d|_])";
    //static Regex methods will cache the regex, so we don't need to worry about that
      var replacement = useComment ? 
                parameter.Value + " /* " + parameter.Name + " */" : 
                parameter.Value;
      statement = Regex.Replace(statement,
                  pattern,
                  replacement);
  }
  return statement;
}

The problem is that:

  • There is no heavy memory pressure.
  • While the string is big, it is not that big.
  • In practice, there is a single replacement for each parameter.

Just for fun, I wasn’t able to reproduce the issue without running the full NH Prof application.

I solved the issue, but I am not entirely pleased with the way I solved it. (That is tomorrow’s post)

Any ideas how to reproduce this?

Any elegant ideas on how to solve this?