Размер стека по умолчанию в операционной системе windows

При разработке программного продукта для операционной системы семейства Windows необходимо помнить об ограничениях, накладываемых на размер данных, которые программа может объявлять и использовать.

Andrey Karpov

При разработке программного продукта для операционной системы семейства Windows необходимо помнить об ограничениях, накладываемых на размер данных, которые программа может объявлять и использовать.

Windows накладывает на программы следующие 3 вида ограничений:

  • Статические данные. Ограничение накладывается на размер самого исходного кода программы и размер статически выделяемой памяти. В языке C++ такие данные обычно представлены переменными, объявленными на глобальном уровне вне процедур. Как для 32-битных, так и для 64-битных программ, ограничение на размер статически выделяемой памяти равно 2 GB.
  • Динамические данные. Это данные, память на которые динамически выделяется во время исполнения программы. В C++ такое выделение обычно осуществляется функцией malloc или оператором new. В 32-битных программах размер динамически выделяемой памяти ограничен 2 GB, в 64-битных — 8 TB.
  • Стековые данные. На них память выделяется при заходе в процедуру и освобождается при её завершении. Максимальный размер стека программы составляет 1 GB и для 32-битных, и для 64-битных приложений. (Размер стека задаётся линковщиком и по умолчанию составляет 1 MB)

У 32-битного приложения запущенного в 32-битной Windows суммарный размер всех перечисленных типов данных не должен превышать 2 GB. (Практически ограничение равно 1.75GB из-за требований к памяти самой операционной системы) 32-битная программа, собранная с ключом /LARGEADDRESSAWARE:YES может выделять до 3-х гигабайт памяти, если 32-битная операционная система Windows запущена с ключом /3gb. Эта же 32-битная программа, запущенная на 64-битной системе, может выделить почти 4 GB памяти (на практике около 3.5 GB).

Заметим, что ограничения на максимальный размер статически-выделяемой и стековой памяти одинаковы для 32-х и 64-х битных Windows приложений. Это связано с форматом типа файлов Portable Executable (PE), который используется в Windows для описания exe и dll файлов. Статические и стековые данные располагаются в первых 2-х GB адресного пространства приложения. Стоит помнить, что данные ограничения накладываются самой операционной системой и не зависят от используемого компилятора.

Библиографический список

  • Steve Lionel. Memory Limits for Applications on Windows
  • Андрей Карпов, Евгений Рыжков. Урок 2. Поддержка 32-битных приложений в 64-битной среде Windows

Присылаем лучшие статьи раз в месяц

Потоком
в Windows называется объект ядра, которому
операционная система выделяет процессорное
время для выполнения приложения. Каждому
потоку принадлежат следующие ресурсы:


код
исполняемой функции;


набор
регистров процессора;


стек
для работы приложения;


стек
для работы операционной системы;


маркер
доступа, который содержит информацию
для системы безопасности.

Все
эти ресурсы образуют контекст потока
в Windows. Кроме дескриптора каждый поток
в Windows также имеет свой идентификатор,
который уникален для потоков выполняющихся
в системе. Идентификаторы потоков
используются служебными программами,
которые позволяют пользователям системы
отслеживать работу потоков.

В
операционных системах Windows различаются
потоки двух типов:


системные
потоки;


пользовательские
потоки.

Системные
потоки выполняют различные сервисы
операционной системы и запускаются
ядром операционной системы.

Пользовательские
потоки служат для решения задач
пользователя и запускаются приложением.

В
работающем приложении различаются
потоки двух типов:


рабочие
потоки (working threads);


потоки
интерфейса пользователя (user interface
threads).

Рабочие
потоки выполняют различные фоновые
задачи в приложении. Потоки интерфейса
пользователя связаны с окнами и выполняют
обработку сообщений, поступающих этим
окнам. Каждое приложение имеет, по
крайней мере, один поток, который
называется первичным (primary) или главным
(main) потоком. В консольных приложениях
это поток, который исполняет функцию
main. В приложениях с графическим интерфейсом
это поток, который исполняет функцию
WinMain.

Создание потоков

Создается
поток функцией CreateThread, которая имеет
следующий прототип:

HANDLE
CreateThread(

LPSECURITY_ATTRIBUTES
lpThreadAttributes, // атрибуты
защиты

DWORD
dwStackSize,
// размер стека потока в байтах

LPTHREAD_START_ROUTINE
IpStartAddress, // адрес
функции

LPVOID
lpParameter,
// аргумент, передаваемый функции потока

DWORD
dwCreationFlags,
// флаги создания потока

LPDWORD
lpThreadld // идентификатор потока );

При
успешном завершении функция CreateThread
возвращает дескриптор созданного потока
и его идентификатор, который является
уникальным для всей системы. В противном
случае эта функция возвращает значение
null.

Кратко
опишем назначение параметров функции
CreateThread.

Параметр
lpThreadAttributes устанавливает атрибуты защиты
создаваемого потока. Если значение
параметра установлено null, то операционная
система сама установит атрибуты защиты
потока, используя настройки по умолчанию.

Параметр
dwstacksize определяет размер стека, который
выделяется потоку при запуске. Если
этот параметр равен нулю, то потоку
выделяется стек, размер которого по
умолчанию равен 1 Мбайт. Это наименьший
размер стека, который может быть выделен
потоку. Если величина параметра
dwstacksize меньше значения, заданного по
умолчанию, то все равно потоку выделяется
стек размером в 1 Мбайт. Операционная
система Windows округляет размер стека до
одной страницы памяти, который обычно
равен 4 Кбайт.

Параметр
lpstartAddress указывает на исполняемую потоком
функцию. Эта функция должна иметь
следующий прототип:

DWORD
WINAPI
имя_функции_потока(LPVOID
lpParameters);

Функции
потока может быть передан единственный
параметр lpParameter, который является
указателем на пустой тип. Это ограничение
следует из того, что функция потока
вызывается операционной системой, а не
прикладной программой. Программы
операционной системы являются исполняемыми
модулями и поэтому они должны вызывать
только функции, сигнатура которых
заранее определена. Поэтому для потоков
определили самый простой список
параметров, который содержит только
указатель. Так как функции потоков
вызываются операционной системой, то
они также получили название функции
обратного вызова.

Параметр
dwCreationFiags определяет, в каком состоянии
будет создан поток. Если значение этого
параметра равно 0, то функция потока
начинает выполняться сразу после
создания потока. Если же значение этого
параметра равно create_suspended, то поток
создается в подвешенном состоянии. В
дальнейшем этот поток можно запустить
вызовом функции ResumeThread.

Параметр
lpThreadid является выходным, т. е. его значение
устанавливает Windows. Этот параметр должен
указывать на переменную, в которую
Windows поместит идентификатор потока.
Этот идентификатор уникален для всей
системы и может в дальнейшем использоваться
для ссылок на поток. Идентификатор
потока главным образом используется
системными функциями и редко функциями
приложения. Действителен идентификатор
потока только на время существования
потока. После завершения потока тот же
идентификатор может быть присвоен
другому потоку. В операционной системе
Windows 98 этот параметр не может быть
равен null. В Windows NT и 2000 допускается
установить его значение в null – тогда
операционная система не возвратит
идентификатор потока.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

I have read that the «standard» and initial stack size on Linux is ~8MB and Windows is ~1MB.

But how does the heap allocation work? Does the OS set a «virtual» size to the process heap like it does for the stack with committed and reserved memory?

trincot's user avatar

trincot

297k33 gold badges237 silver badges276 bronze badges

asked Nov 5, 2011 at 1:25

Julio Vga's user avatar

2

Classically, the layout of a program has the ‘text’ (or ‘code’) segment at the low end of memory, followed by the fixed data (‘data’ and ‘bss’ segments), followed by a gap, with the stack growing downwards from high memory. The gap in the middle becomes the heap, which grows from the end of the data towards the stack.

Things are more complex with threaded programs, shared libraries loaded, shared memory, etc.

The initial stack size is o/s dependent. The initial heap size is logically zero, but tends to grow almost immediately (as the program and the shared libraries are loaded).

answered Nov 5, 2011 at 1:35

Jonathan Leffler's user avatar

Jonathan LefflerJonathan Leffler

718k138 gold badges893 silver badges1260 bronze badges

4

There is no general «standard size». Individual operating systems will have a default size, but usually they can be altered with appropriate parameters in the program image or on the command line.

C executes in a vast range of systems from tiny microprocessors with only a few hundred bytes of available memory to gigantic processor arrays with hundreds of gigabytes.

In your larger systems (including most Windows and Linux environments) the stack and heap will be assigned to segments that can be expanded, so that physical memory for maximum sizes does not need to be pre-reserved. Many micros, though, lack memory mapping hardware and the sizes must be pre-reserved (though sometimes the stack and heap are made to grow towards each other so that there’s only one common limit).

answered Nov 5, 2011 at 1:33

Hot Licks's user avatar

Hot LicksHot Licks

46.7k17 gold badges93 silver badges151 bronze badges

2

I have read that the «standard» and initial stack size on Linux is ~8MB and Windows is ~1MB.

But how does the heap allocation work? Does the OS set a «virtual» size to the process heap like it does for the stack with committed and reserved memory?

trincot's user avatar

trincot

297k33 gold badges237 silver badges276 bronze badges

asked Nov 5, 2011 at 1:25

Julio Vga's user avatar

2

Classically, the layout of a program has the ‘text’ (or ‘code’) segment at the low end of memory, followed by the fixed data (‘data’ and ‘bss’ segments), followed by a gap, with the stack growing downwards from high memory. The gap in the middle becomes the heap, which grows from the end of the data towards the stack.

Things are more complex with threaded programs, shared libraries loaded, shared memory, etc.

The initial stack size is o/s dependent. The initial heap size is logically zero, but tends to grow almost immediately (as the program and the shared libraries are loaded).

answered Nov 5, 2011 at 1:35

Jonathan Leffler's user avatar

Jonathan LefflerJonathan Leffler

718k138 gold badges893 silver badges1260 bronze badges

4

There is no general «standard size». Individual operating systems will have a default size, but usually they can be altered with appropriate parameters in the program image or on the command line.

C executes in a vast range of systems from tiny microprocessors with only a few hundred bytes of available memory to gigantic processor arrays with hundreds of gigabytes.

In your larger systems (including most Windows and Linux environments) the stack and heap will be assigned to segments that can be expanded, so that physical memory for maximum sizes does not need to be pre-reserved. Many micros, though, lack memory mapping hardware and the sizes must be pre-reserved (though sometimes the stack and heap are made to grow towards each other so that there’s only one common limit).

answered Nov 5, 2011 at 1:33

Hot Licks's user avatar

Hot LicksHot Licks

46.7k17 gold badges93 silver badges151 bronze badges

2

Изображение 122683

Вы смотрите на парня, который сделал этот выбор. Дэвид Катлер и его команда выбрали один мегабайт в качестве размера стека по умолчанию. Ничего общего с .NET или С#, это было прибито, когда они создали Windows NT. Один мегабайт — это то, что он выбирает, когда заголовок EXE программы или вызов winapi CreateThread() не задают размер стека явно. Что является нормальным способом, почти любой программист оставляет его ОС для выбора размера.

Этот выбор, вероятно, предшествует дизайну Windows NT, история слишком мутная об этом. Было бы хорошо, если бы Катлер написал бы книгу об этом, но он никогда не был писателем. Он был чрезвычайно влиятелен на то, как работают компьютеры. Его первый дизайн ОС — RSX-11M, 16-разрядная операционная система для компьютеров DEC (Digital Equipment Corporation). Это сильно повлияло на Gary Kildall CP/M, первую достойную ОС для 8-битных микропроцессоров. Что сильно повлияло на MS-DOS.

Следующим его проектом стала VMS, операционная система для 32-разрядных процессоров с поддержкой виртуальной памяти. Очень успешный. Его следующий был отменен DEC примерно в то время, когда компания начала распадаться, не имея возможности конкурировать с дешевым оборудованием для ПК. Кий Microsoft, они сделали ему предложение, от которого он не мог отказаться. К нему присоединились и многие из его коллег. Они работали над VMS v2, более известной как Windows NT. DEC расстроилась из-за этого, деньги сменили руки, чтобы урегулировать это. Является ли VMS уже одним мегабайтом, я не знаю, я знаю только RSX-11. Это маловероятно.

Достаточно истории. Один мегабайт — это лот, реальная нить редко потребляет больше, чем несколько горстей килобайт. Таким образом, мегабайт на самом деле довольно расточительный. Тем не менее, это те виды отходов, которые вы можете себе позволить в оперативной системе виртуальной памяти с запросами по требованию, что мегабайт — это просто виртуальная память. Просто номера процессора, по одному на каждые 4096 байт. Вы никогда не используете физическую память, оперативную память в машине, пока вы на самом деле не обратитесь к ней.

Это лишнее чрезмерное значение в программе .NET, потому что один мегабайт был первоначально выбран для размещения собственных программ. Они, как правило, создают большие стековые фреймы, сохраняя строки и буферы (массивы) в стеке. Печально известный как вектор атаки вредоносного ПО, переполнение буфера может манипулировать программой данными. Не так, как работают .NET-программы, строки и массивы выделяются на куче GC и проверяется индексация. Единственный способ выделить пространство в стеке с помощью С# — это небезопасное ключевое слово stackalloc.

Единственное нетривиальное использование стека в .NET — это дрожание. Он использует стек вашего потока для компиляции MSIL для компиляции MSIL в машинный код. Я никогда не видел и не проверял, сколько места он требует, скорее зависит от характера кода и от того, включен ли оптимизатор, но несколько десятков килобайт — это грубое предположение. В противном случае, как этот сайт получил свое имя, переполнение стека в .NET-программе является довольно фатальным. Недостаточно свободного места (менее 3 килобайт), чтобы все еще надежно использовать JIT любой код, который пытается поймать исключение. Kaboom для настольных компьютеров является единственным вариантом.

И последнее, но не менее важное:.NET-программа делает что-то довольно непродуктивное со стеком. CLR зафиксирует стек потока. Это дорогое слово, что означает, что он не просто резервирует размер стека, но также гарантирует, что пространство зарезервировано в файле подкачки операционной системы, поэтому при необходимости стек всегда может быть заменен. Неспособность совершить является фатальной ошибкой и безоговорочно завершает программу. Это происходит только на машине с очень маленькой ОЗУ, которая запускает полностью слишком много процессов, такая машина превратится в патоку, прежде чем программы начнут умирать. Возможная проблема 15 лет назад, а не сегодня. Программисты, которые настраивают свою программу, чтобы действовать как гоночный автомобиль F1, используют <disableCommitThreadStack> в своем файле .config.

Fwiw, Катлер не прекратил разработку операционных систем. Эта фотография была сделана, когда он работал над Azure.


Обновление, я заметил, что .NET больше не выполняет стек. Не совсем точно, когда и почему это произошло, я слишком долго не проверял. Я предполагаю, что это изменение дизайна произошло где-то около .NET 4.5. Довольно разумные изменения.


В форумах люди часто упоминают, что 64-битные версии программ поглощают больший объем памяти и стека. При этом обычно ссылаются на то, что размеры данных стали в 2 раза больше. Однако это необоснованное утверждение, так как размер большинства типов (char, short, int, float) в языке Си/Си++ остался прежним на 64-битных системах. Конечно, например, увеличился размер указателей, но ведь не все данные в программе состоят из указателей. Причины роста потребляемой памяти и стека более сложны. Я решил подробнее исследовать данный вопрос.

В данной заметке я поговорю о стеке, а в будущем планирую обсудить выделение памяти и размер двоичного кода. И еще хочу сразу заметить, что статья посвящена языку Си/Си++ и среде разработки Visual Studio.

До недавнего времени я считал, что код 64-битной программы может поглощать стек не быстрее чем в два раза по сравнению с 32-битным кодом. Основываясь на этом предположении, я рекомендовал в статьях на всякий случай увеличивать стек программы в два раза. Однако теперь я выяснил неприятный факт. Поглощение стека может вырасти существенно больше чем в два раза. Я был удивлен, поскольку ранее считал рост стека в два раза самым пессимистическим вариантом развития событий. Причина моих необоснованных надежд станет понятна чуть позже. Рассмотрим теперь, как в 64-битной программе передаются параметры при вызове функций.

При разработке соглашений по вызовам (calling conventions) для архитектуры x86-64 решили положить конец существованию различных вариантов вызова функций. В Win32 существовал целый ряд соглашений о вызове: stdcall, cdecl, fastcall, thiscall и так далее. В Win64 только одно «родное» соглашение по вызовам. Модификаторы подобные __cdecl компилятором игнорируются. Думаю, что все согласятся в благородстве такого резкого сокращение числа соглашений.

Соглашение по вызовам на платформе x86-64 похоже на соглашение fastcall, существующее в x86. В x64-соглашении первые четыре целочисленных аргумента (слева направо) передаются в 64-битных регистрах, выбранных специально для этой цели:

RCX: 1-й целочисленный аргумент
RDX: 2-й целочисленный аргумент
R8: 3-й целочисленный аргумент
R9: 4-й целочисленный аргумент

Остальные целочисленные аргументы передаются через стек. Указатель «this» считается целочисленным аргументом, поэтому он всегда помещается в регистр RCX. Если передаются значения с плавающей точкой, то первые четыре из них передаются в регистрах XMM0-XMM3, а последующие — через стек.

Из этой информации я ранее сделал вывод, что 64-битная программа во многих случаях может экономить стековую память по сравнению с 32-битной. Ведь если параметры передаются через регистры, код функции короткий и нет необходимости сохранять аргументы в памяти (стеке), то размер используемой стековой памяти должен сократиться. Но это не так.

Хотя аргументы могут быть переданы в регистрах, компилятор все равно резервирует для них место в стеке, уменьшая значение регистра RSP (указателя стека). Как минимум, каждая функция должна резервировать в стеке 32 байта (четыре 64-битных значения, соответствующие регистрам RCX, RDX, R8, R9). Это пространство в стеке позволяет легко сохранить содержимое переданных в функцию регистров в стеке. От вызываемой функции не требуется сбрасывать в стек входные параметры, переданные через регистры, но резервирование места в стеке при необходимости позволяет это сделать. Если передается более четырех целочисленных параметров, в стеке нужно зарезервировать соответствующее дополнительное пространство.

Рассмотрим пример. Некая функция передает два целочисленных параметра дочерней функции. Компилятор положит значения аргументов в регистры RCX и RDX и при этом вычтет 32 байта из регистра RSP. Вызываемая функция может обратиться к параметрам через регистры RCX и RDX. Если же коду этой функции данные регистры понадобятся для какой-то иной цели, он сможет скопировать их содержимое в зарезервированное пространство стека размером 32 байта.

Описанная особенность приводит к существенному возрастанию скорости поглощения стека. Даже если функция не имеет параметров, то от стека все равно будет «откушено» 32 байта, которые затем никак не используются. Смысл использования такого неэкономного механизма я не уловил. Что-то говорится про унификацию и упрощение отладки, но как-то расплывчато.

Обратим внимание еще на один момент. Указатель стека RSP должен перед очередным вызовом функции быть выровнен по границе 16 байт. Таким образом, суммарный размер используемого стека при вызове в 64-битном коде функции без параметров составляет: 8 (адрес возврата) + 8 (выравнивание) + 32 (резерв для аргументов) = 48 байт!

Рассмотрим, к чему это может приводить на практике. Здесь и далее для экспериментов я буду использовать Visual Studio 2010. Составим рекурсивную функцию вида:

void StackUse(size_t *depth)
{
  volatile size_t *ptr = 0;

  if (depth != NULL)
    ptr = depth;

  cout << *ptr << endl;

  (*ptr)++;

  StackUse(depth);

  (*ptr)--;
}

Функция немного запутанна, чтобы оптимизатор не превратил ее в «ничто». Основное здесь следующее: функция имеет аргумент типа указатель и одну локальную переменную, также типа указатель. Посмотрим, сколько стека потребляет функция в 32-битном и 64-битном варианте и сколько раз она может быть рекурсивно вызвана при стеке размером 1 мегабайт (размер по умолчанию).

Release 32-bit: последнее выведенное число (глубина стека) — 51331
Компилятор использует при вызове данной функции 20 байт.

Release 64-bit: последнее выведенное число — 21288
Компилятор использует при вызове данной функции 48 байт.

Таким образом, 64-битный вариант функции StackUse оказывается прожорливее 32-битного в более чем в 2 раза.

Замечу, что изменение правил выравнивания данных также может оказывать влияние на размер поглощаемого стека. Предположим, что функция принимает в качестве аргумента структуру:

struct S
{
  char a;
  size_t b;
  char c;
};

void StackUse(S s) { ... }

Размер структуры ‘S’ из-за изменений правил выравнивания и изменения размера члена ‘b’ вырастет с 12 до 24 байт при перекомпиляции в 64-битном режиме. Структура передается в функцию по значению. А, следовательно, структура в стеке также займет в два раза больше памяти.

Неужели все так плохо? Нет. Не следует забывать про большее количество регистров имеющихся в распоряжении 64-битного компилятора. Усложним код экспериментальной функции:

void StackUse(size_t *depth, char a, int b)
{
  volatile size_t *ptr = 0;

  int c = 1;
  int d = -1;

  for (int i = 0; i < b; i++)
    for (char j = 0; j < a; j++)
      for (char k = 0; k < 5; k++)
        if (*depth > 10 && k > 2)
        {
          c += j * k - i;
          d -= (i - j) * c;
        }

  if (depth != NULL)
    ptr = depth;

  cout << c << " " << d << " " << *ptr << endl;
  (*ptr)++;

  StackUse(depth, a, b);

  (*ptr)--;
}

Результаты запуска:

Release 32-bit: последнее выведенное число — 16060
Компилятор использует при вызове данной функции уже 64 байта.

Release 64-bit: последнее выведенное число — 21310
Компилятор использует при вызове данной функции по-прежнему 48 байт.

Для данного примера 64-битному компилятору удалось использовать дополнительные регистры и построить более эффективный код, что позволило сократить количество используемой стековой памяти!

Выводы

  1. Невозможно предсказать, сколько стековой памяти будет использовать 64-битный вариант программы по сравнению с 32-битным. Размер может быть как меньше (что маловероятно), так и значительно больше.
  2. Для 64-битной программы на всякий случай стоит увеличить объем зарезервированного стека в 2-3 раза. Лучше в 3 раза для спокойствия. Для этого в настройках проекта имеется параметр Stack Reserve Size (ключ /STACK:reserve). По умолчанию размер стека составляет 1 мегабайт.
  3. Не следует беспокоиться, что 64-битная программа потребляет больше стековой памяти. Физической памяти в 64-битных системах значительно больше. Стек размером 2 мегабайта на 64-битной системе с 8 гигабайтами памяти, занимает меньший процент памяти, чем 1 мегабайт стека в 32-битной системе с 2 гигабайтами памяти.

Дополнительные ссылки

  1. Raymond Chen. The history of calling conventions, part 5: amd64. http://www.viva64.com/go.php?url=325
  2. Kevin Frei. x64 ABI vs. x86 ABI (aka Calling Conventions for AMD64 & EM64T). http://www.viva64.com/go.php?url=326
  3. MSDN. x64 Software Conventions. http://www.viva64.com/go.php?url=327
  4. Wikipedia. x86 calling conventions. http://www.viva64.com/go.php?url=328

Размер стека потока


Каждый новый поток получает свое собственное пространство стека, состоящее, и из виртуальной памяти в файле подкачки, и
зарезервированной памяти. Система помещает одностраничные блоки из зарезервированной памяти стека, как требуется, до тех пор, пока
стек не сможет больше расти.



Заданный по умолчанию размер для переданной и зарезервированной памяти устанавливается в заголовке исполняемого
файла. Заданная по умолчанию зарезервированная память равна одному мегабайту. Чтобы установить другой
заданный по умолчанию размер стека, используйте инструкцию
STACKSIZE
в файле определения модуля (.DEF). Ваш компоновщик может также поддерживать параметр командной строки для установки
размера стека. Для получения дополнительной информации, см. документацию, включенную в ваш компоновщик.


Потоки, которые вызывают библиотеки языка
C периода исполнения или Windows API, должны обеспечит достаточное место в стеке для
использования этих функций. Не уменьшайте зарезервированный размер стека ниже 64 килобайт.

Чтобы увеличить объем свободного пространства стека, которое должно передаваться вначале для потока,
установите значение в параметре

dwStackSize
функции CreateThread
или CreateRemoteThread.
Это значение округляется до ближайшей страницы. Вызов, который создает поток, завершается ошибкой, если нет достаточно
памяти, чтобы передать на хранение или зарезервировать количество требуемых байтов. Если параметр
dwStackSize
меньше чем заданный по умолчанию резервный размер, новый поток использует заданный по умолчанию резервный размер. Если параметр
dwStackSize
больше чем заданный по умолчанию резервный размер, резервный размер округляется до ближайшего числа кратного 1 Мбайту.



Windows XP: Если параметр
dwCreationFlags
функции CreateThread
или
CreateRemoteThread
STACK_SIZE_PARAM_IS_A_RESERVATION,
параметр
dwStackSize
устанавливает объем свободного пространства стека, которое должно быть вначале зарезервировано для потока.


Стек освобождается, когда завершается работа потока.


Hosted by uCoz

Понравилась статья? Поделить с друзьями:
  • Раздача вай фай с ноутбука windows 10 через модем
  • Размер системного диска под windows 10
  • Раздача wifi с ноутбука windows 10 через командную строку
  • Размер рабочего стола больше размера монитора windows 10
  • Разделить жесткий диск на разделы windows 10 программа бесплатная