Насколько я знаю, каждый поток получает отдельный стек, когда поток создается операционной системой. Интересно, есть ли у каждого потока отдельная куча?
Насколько я знаю, каждый поток получает отдельный стек, когда поток создается операционной системой. Интересно, есть ли у каждого потока отдельная куча?
Ответы:
Нет. Все потоки используют общую кучу.
У каждого потока есть собственный стек , из которого он может быстро добавлять и удалять элементы. Это делает память на основе стека быстрой, но если вы используете слишком много памяти стека, как это происходит при бесконечной рекурсии, вы получите переполнение стека.
Поскольку все потоки используют одну и ту же кучу, доступ к распределителю / освободителю должен быть синхронизирован. Существуют различные методы и библиотеки, позволяющие избежать конфликта распределителей .
Некоторые языки позволяют создавать частные пулы памяти или отдельные кучи, которые можно назначать одному потоку.
you will get a stack overflow.
Переполнение стека при переполнении стека!
По умолчанию C имеет только одну кучу.
Тем не менее, некоторые распределители, поддерживающие потоки, будут разделять кучу так, чтобы у каждого потока была своя область для выделения. Идея в том, что это должно улучшить масштабирование кучи.
Одним из примеров такой кучи является Hoard .
Зависит от ОС. Стандартная среда выполнения c в Windows и Unices использует общую кучу между потоками. Это означает блокировку каждого malloc / free.
В Symbian, например, каждый поток имеет свою собственную кучу, хотя потоки могут совместно использовать указатели на данные, размещенные в любой куче. На мой взгляд, дизайн Symbian лучше, поскольку он не только устраняет необходимость блокировки во время выделения / освобождения, но также способствует четкой спецификации владения данными между потоками. Также в том случае, когда поток умирает, он принимает все объекты, которые он выделил вместе с ним, то есть он не может пропускать объекты, которые он выделил, что является важным свойством для мобильных устройств с ограниченной памятью.
Erlang также следует аналогичной схеме, где «процесс» действует как единица сборки мусора. Все данные передаются между процессами путем копирования, за исключением двоичных блобов, которые подсчитываются по ссылкам (я думаю).
Это зависит от того, что именно вы имеете в виду, говоря «куча».
Все потоки совместно используют адресное пространство, поэтому объекты, размещенные в куче, доступны из всех потоков. Технически стеки также являются общими в этом смысле, т.е. ничто не мешает вам получить доступ к стеку другого потока (хотя это почти никогда не имело бы смысла делать это).
С другой стороны, для выделения памяти используются структуры кучи . Именно здесь выполняется вся бухгалтерия по распределению памяти кучи. Эти структуры тщательно организованы, чтобы минимизировать конкуренцию между потоками, поэтому некоторые потоки могут совместно использовать структуру кучи (арену), а некоторые могут использовать отдельные арены.
См. Следующий поток для прекрасного объяснения деталей: Как malloc работает в многопоточной среде?
Обычно потоки совместно используют кучу и другие ресурсы, однако существуют потоковые конструкции, которые этого не делают. Среди этих потоковоподобных конструкций - облегченные процессы Erlang и полнофункциональные процессы UNIX (созданные с помощью вызова fork()
). Вы также можете работать над параллелизмом между несколькими машинами, и в этом случае ваши возможности межпоточного взаимодействия значительно более ограничены.
Вообще говоря, все потоки используют одно и то же адресное пространство и поэтому обычно имеют только одну кучу.
Однако все может быть немного сложнее. Возможно, вы ищете локальное хранилище потоков (TLS), но оно хранит только отдельные значения.
Специфично для Windows: TLS-пространство можно выделить с помощью TlsAlloc и освободить с помощью TlsFree (обзор здесь ). Опять же, это не куча, а просто DWORD.
Как ни странно, Windows поддерживает несколько куч для каждого процесса. Дескриптор кучи можно сохранить в TLS. Тогда у вас будет что-то вроде «локальной кучи потока». Однако другим потокам неизвестен только дескриптор, они по-прежнему могут обращаться к его памяти с помощью указателей, поскольку это все то же адресное пространство.
РЕДАКТИРОВАТЬ : Некоторые распределители памяти (в частности, jemalloc во FreeBSD) используют TLS для назначения «арен» потокам. Это сделано для оптимизации распределения для нескольких ядер за счет уменьшения накладных расходов на синхронизацию.
В операционной системе FreeRTOS задачи (потоки) используют одну и ту же кучу, но каждая из них имеет свой собственный стек. Это очень удобно при работе с архитектурами с низким энергопотреблением и низким объемом оперативной памяти, потому что к одному и тому же пулу памяти могут обращаться / совместно использовать несколько потоков, но это имеет небольшую загвоздку, разработчик должен иметь в виду, что механизм синхронизации malloc and free необходим, поэтому необходимо использовать какой-то тип синхронизации / блокировки процесса при выделении или освобождении памяти в куче, например семафор или мьютекс.