Недостаточно места в стеке ValueType - PullRequest
4 голосов
/ 10 июня 2011

Насколько я понимаю, каждый новый поток в .Net выделяет 1 МБ стекового пространства .Кроме того, я понимаю, что типы значений хранятся в стеке, а не в куче ...

Так что мой вопрос таков;Означает ли это такое поведение, что любые объявления переменных ValueType ограничены 1 МБ дискового пространства?То, что чем больше ValueTypes вы объявили в вашей текущей области видимости, тем меньше может быть эффективный стек вызовов, и в какой-то момент это означает, что объявление (ради аргумента) ~ 260 000 int будет использовать все пространство стека?

1 Ответ

4 голосов
/ 10 июня 2011

Наиболее плодотворный ответ на этот тип вопросов, как правило, идет и проверить. Другие говорили вам, что вам не стоит об этом беспокоиться, и они вроде правы. Все статьи, на которые есть ссылки, великолепны и их стоит прочитать. В большинстве практических случаев вам не потребуется около 1 МБ локальных переменных.

Но что, если вы хотите знать погоду, вы на самом деле можете иметь 1 МБ локальных переменных стоимостью? Как отмечали другие, это детали реализации, и результаты могут отличаться в зависимости от платформы, версии компилятора, поставщика и т. Д.

Давайте проверим это сами и посмотрим, что возможно, а что нет. Я на x64 машине с компилятором VS2010 и C # 4.0.

Вот мой код:

using System;

namespace SO6301703
{
    struct s64b
    {
        public long f1;
        public long f2;
        public long f3;
        public long f4;
        public long f5;
        public long f6;
        public long f7;
        public long f8;
    }

    struct s256b
    {
        public s64b f1;
        public s64b f2;
        public s64b f3;
        public s64b f4;
    }

    struct s1kb
    {
        public s256b f1;
        public s256b f2;
        public s256b f3;
        public s256b f4;
    }

    struct s8kb
    {
        public s1kb f1;
        public s1kb f2;
        public s1kb f3;
        public s1kb f4;
        public s1kb f5;
        public s1kb f6;
        public s1kb f7;
        public s1kb f8;
    }

    struct s64kb
    {
        public s8kb f1;
        public s8kb f2;
        public s8kb f3;
        public s8kb f4;
        public s8kb f5;
        public s8kb f6;
        public s8kb f7;
        public s8kb f8;

    }

    struct s512kb
    {
        public s64kb f1;
        public s64kb f2;
        public s64kb f3;
        public s64kb f4;
        public s64kb f5;
        public s64kb f6;
        public s64kb f7;
        public s64kb f8;

    }

    struct s1Mb
    {
        public s512kb f1;
        public s512kb f2;

    }

    class Program
    {
        static void Main(string[] args)
        {
            unsafe { Console.WriteLine(sizeof(s1Mb)); }
            s1Mb test;
        }
    }
}

Когда я компилирую и запускаю этот код, я получаю исключение переполнения стека. Это означает, что, по крайней мере, в некоторых случаях вы действительно ограничены пространством стека. И это означает, что чем больше у вас локальных переменных, тем меньше стека у вас осталось для вызовов методов, рекурсии и т. Д.

Еще раз: эти соображения вряд ли когда-либо практичны. Если вы выделяете локальные переменные стоимостью 1 МБ, вы, скорее всего, делаете что-то не так. Но если вам все равно интересно ... теперь вы знаете.

...