16

How many parameters can you pass to a string.Format() method?

There must be some sort of theoretical or enforced limit on it. Is it based on the limits of the params[] type or the memory usage of the app that is using it or something else entirely?

4 Answers 4

21

OK, I emerge from hiding... I used the following program to verify what was going on and while Marc pointed out that a string like this "{0}{1}{2}...{2147483647}" would succeed the memory limit of 2 GiB before the argument list, my findings did't match yours. Thus the hard limit, of the number of parameters you can put in a string.Format method call has to be 107713904.

int i = 0;
long sum = 0;
while (sum < int.MaxValue)
{
    var s = sizeof(char) * ("{" + i + "}").Length;
    sum += s; // pseudo append
    ++i;
}
Console.WriteLine(i);
Console.ReadLine();

Love the discussion people!

Sign up to request clarification or add additional context in comments.

Comments

19

Not as far as I know...

well, the theoretical limit would be the int32 limit for the array, but you'd hit the string length limit long before that, I guess...

Just don't go mad with it ;-p It may be better to write lots of small fragments to (for example) a file or response, than one huge hit.

edit - it looked like there was a limit in the IL (0xf4240), but apparently this isn't quite as it appears; I can make it get quite large (2^24) before I simply run out of system memory...


Update; it seems to me that the bounding point is the format string... those {1000001}{1000002} add up... a quick bit of math (below) shows that the maximum useful number of arguments we can use is 206,449,129:

    long remaining = 2147483647;// max theoretical format arg length
    long count = 10; // i.e. {0}-{9}
    long len = 1;
    int total = 0;
    while (remaining >= 0) {
        for(int i = 0 ; i < count && remaining >= 0; i++) {
            total++;
            remaining -= len + 2; // allow for {}
        }
        count *= 10;
        len++;
    }

    Console.WriteLine(total - 1);

7 Comments

wow, an arbitrary undocumented limit... I don't like that. +1 for research.
The CLR doesn't not support objects grater than 2GiB. Because the format method pre-allocates a StringBuilder with 8 characters for each argument one theoretical limit would be int.MaxValue/(sizeof(char)*8) which equals 134,217,728
It's ok, I'll post it as an answer for John . . . JOKING! I'm only joking :) +1 Excellent answer Marc
@John - are you sure about the 8 char detail? There is only one StringBuilder, no matter the number of arguments...
Yes! Goto string.Format(IFormatProvider,string format, params object[] args) it tries to allocate this new StringBuilder(format.Length + (args.Length * 8)); which eventually calls FastAllocateString(int capacity) I can only assume that it will allocate 2 bytes of every character.
|
4

Expanding on Marc's detailed answer.

The only other limitation that is important is for the debugger. Once you pass a certain number of parameters directly to a function, the debugger becomes less functional in that method. I believe the limit is 64 parameters.

Note: This does not mean an array with 64 members, but 64 parameters passed directly to the function.

You might laugh and say "who would do this?" which is certainly a valid question. Yet LINQ makes this a lot easier than you think. Under the hood in LINQ the compiler generates a lot of code. It's possible that for a large generate SQL query where more than 64 fields are selected that you would hit this issue. Because the compiler under the hood would need to pass all of the fields to the constructor of an anonymous type.

Still a corner case.

Comments

3

Considering that both the limit of the Array class and the String class are the upper limit of Int32 (documented at 2,147,483,647 here: Int32 Structure), it is reasonable to believe that this value is the limit of the number string of format parameters.

Update Upon checking reflector, John is right. String.Format, using the Red Gate Reflector, shows the ff:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
    builder.AppendFormat(provider, format, args);
    return builder.ToString();
}

The format.Length + (args.Length * 8) part of the code is enough to kill most of that number. Ergo, '2,147,483,647 = x + 8x' leaves us with x = 238,609,294 (theoretical).

It's far less than that of course; as the guys in the comments mentioned the string hitting the string length limit earlier is quite likely.

Maybe someone should just code this into a machine problem! :P

4 Comments

Dude, you really should just provide an answer ;)
Besides - in both cases, you're more hampered by the format string.... {1000000}{1000001}{1000002} etc... it adds up quickly...
@Marc - Yeah, that format string itself should hit the 2 GiB limit a lot sooner...
@Jon Limjap - well it's sort of redundant, I like comments ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.