Как называются программы с автоматической загрузкой памяти
Обновлено: 20.11.2024
Учитывая, что память разделена на четыре сегмента: данные, куча, стек и код, где находятся глобальные переменные, статические переменные, постоянные типы данных, локальные переменные (определенные и объявленные в функциях), переменные (в основной функции ), указатели и динамически выделяемое пространство (с использованием malloc и calloc) сохраняются в памяти?
Я думаю, что они будут распределены следующим образом:
- Глобальные переменные -------> данные
- Статические переменные -------> данные
- Постоянные типы данных -----> код
- Локальные переменные (объявленные и определенные в функциях) --------> стек
- Переменные, объявленные и определенные в основной функции -----> куча
- Указатели (например, char *arr , int *arr ) -------> куча
- Динамически выделяемое пространство (с использованием malloc и calloc) --------> стек
Я имею в виду эти переменные только с точки зрения C.
Пожалуйста, поправьте меня, если я ошибаюсь, так как я новичок в C.
Большинство мелких деталей, вероятно, зависят от реализации. (То есть ничто не запрещает компилятору C/среде выполнения, которая выделяет в куче все, включая «фреймы стека».)
9 ответов 9
Вы правильно ответили на некоторые вопросы, но тот, кто написал вопросы, обманул вас по крайней мере в одном вопросе:
- глобальные переменные -------> данные (правильно)
- статические переменные -------> данные (правильно)
- постоянные типы данных -----> код и/или данные. Рассмотрим строковые литералы для ситуации, когда сама константа будет храниться в сегменте данных, а ссылки на нее будут встроены в код
- локальные переменные (объявлены и определены в функциях) --------> стек (правильно)
- переменные, объявленные и определенные в основной функции ----->
heap, также складываются (учитель пытался вас обмануть) - указатели (пример: char *arr , int *arr ) ------->
кучаданные или стек, в зависимости от контекста. C позволяет объявить глобальный или статический указатель, и в этом случае сам указатель окажется в сегменте данных. - динамически выделяемое пространство (с использованием malloc , calloc , realloc ) -------->
стеккуча
Стоит отметить, что "стек" официально называется "классом автоматического хранения".
Также стоит отметить, что куча официально никак не называется. Выделенная память откуда-то берется, в стандарте нет имени для этого "где-то".
В некоторых системах (а именно в Linux и *BSD) есть также alloca, который работает аналогично malloc, но выделяет стек.
Думаю, вы поняли, что я имел в виду, просто чтобы было ясно: я не хотел спросить, где хранится a, а скорее, где находится блок памяти, на который указывает a.
@myradio В объявлении int a[10] или int a[b] нет указателя, они объявляют массивы. Эти массивы помещаются в автоматическую область памяти.
Для тех будущих посетителей, которым может быть интересно узнать об этих сегментах памяти, я пишу важные моменты о 5 сегментах памяти в C:
Некоторые советы:
- Каждый раз, когда выполняется программа C, для выполнения программы в ОЗУ выделяется некоторая память. Эта память используется для хранения часто исполняемого кода (бинарных данных), программных переменных и т. д. Об этом говорят следующие сегменты памяти:
- Обычно существует три типа переменных:
- Локальные переменные (также называемые автоматическими переменными в C)
- Глобальные переменные
- Статические переменные
- У вас могут быть глобальные статические или локальные статические переменные, но три вышеуказанных типа являются родительскими.
5 сегментов памяти в C:
- Сегмент кода, также называемый текстовым сегментом, представляет собой область памяти, содержащую часто выполняемый код.
- Часто сегмент кода доступен только для чтения, чтобы избежать риска переопределения программными ошибками, такими как переполнение буфера и т. д.
- Сегмент кода не содержит программных переменных, таких как локальные переменные (также называемые автоматическими переменными в C), глобальные переменные и т. д.
- На основе реализации C сегмент кода может также содержать строковые литералы, доступные только для чтения. Например, когда вы делаете printf("Hello, world"), тогда строка "Hello, world" создается в сегменте кода/текста. Вы можете проверить это с помощью команды size в ОС Linux.
Сегмент данных разделен на две указанные ниже части и обычно находится ниже области кучи или, в некоторых реализациях, над стеком, но сегмент данных никогда не располагается между кучей и областью стека.
2. Неинициализированный сегмент данных
- Этот сегмент также известен как bss.
- Это часть памяти, которая содержит:
- Неинициализированные глобальные переменные(включая переменные-указатели)
- Неинициализированные постоянные глобальные переменные.
- Неинициализированные локальные статические переменные.
- Любая неинициализированная глобальная или статическая локальная переменная будет храниться в неинициализированном сегменте данных.
- Например: глобальная переменная int globalVar; или статическая локальная переменная static int localStatic; будет храниться в неинициализированном сегменте данных.
- Если вы объявите глобальную переменную и инициализируете ее как 0 или NULL, тогда она все равно перейдет в неинициализированный сегмент данных или bss.
3. Сегмент инициализированных данных
- В этом сегменте хранятся:
- Инициализированные глобальные переменные(включая переменные-указатели)
- Инициализированные постоянные глобальные переменные.
- Инициализированы локальные статические переменные.
- Например: глобальная переменная int globalVar = 1; или статическая локальная переменная static int localStatic = 1; будет храниться в инициализированном сегменте данных.
- Этот сегмент можно разделить на инициализированную область только для чтения и инициализированную область чтения-записи. Инициализированные постоянные глобальные переменные помещаются в инициализированную область только для чтения, а переменные, значения которых могут быть изменены во время выполнения, помещаются в инициализированную область чтения-записи.
- Размер этого сегмента определяется размером значений в исходном коде программы и не изменяется во время выполнения.
- Сегмент стека используется для хранения переменных, созданных внутри функций (функция может быть основной или определяемой пользователем функцией), таких переменных, как
- Локальные переменные функции (включая переменные-указатели)
- Аргументы, переданные функции
- Обратный адрес
- Переменные, хранящиеся в стеке, будут удалены, как только завершится выполнение функции.
- Этот сегмент предназначен для поддержки динамического выделения памяти. Если программист хочет выделить часть памяти динамически, то в C это делается с помощью методов malloc, calloc или realloc.
- Например, если int* prt = malloc(sizeof(int) * 2), то восемь байтов будут выделены в куче, а адрес памяти этого места будет возвращен и сохранен в переменной ptr. Переменная ptr будет находиться либо в стеке, либо в сегменте данных, в зависимости от того, как она объявлена/используется.
Относительно "хранится в неинициализированном сегменте данных" (несколько экземпляров): Вы имеете в виду "хранится в неинициализированном сегменте данных"?
@PeterMortensen Я имею в виду и то, и другое. "Любая неинициализированная глобальная или статическая локальная переменная будет храниться в неинициализированном сегменте данных"
Современный GNU binutils ld отделяет .rodata , помещая его в собственный доступный только для чтения сегмент non-exec, отдельный от кода (я тестировал на GNU/Linux). Это означает, что статические константы, такие как строковые литералы, больше не являются возможными кандидатами для гаджетов Spectre/ROP, поскольку они находятся на неисполняемых страницах.
Исправил ваши неправильные предложения
локальные постоянные переменные -----> стек
инициализированная глобальная константная переменная -----> сегмент данных
неинициализированная глобальная константная переменная -----> bss
переменные объявлены и определены в основной функции -----> стек
pointers(ex:char *arr,int *arr) -------> размер этой переменной указателя будет в стеке.
Учтите, что вы выделяете память из n байтов (используя malloc или calloc ) динамически, а затем создаете переменную указателя, чтобы указать на нее. Теперь, когда n байтов памяти находятся в куче, а переменная указателя требует 4 байта (для 64-битной машины 8 байтов), которые будут в стеке для хранения начального указателя n байтов фрагмента памяти.
Примечание. Переменные-указатели могут указывать на память любого сегмента.
динамически выделяемое пространство (с использованием malloc, calloc) --------> куча
Не могли бы вы указать на следующей карте памяти, где находятся стек и куча? Я не уверен, что это правильный вопрос, поскольку стек и память могут быть применимы только во время выполнения. КАРТА ПАМЯТИ: "текстовые данные bss dec шестнадцатеричное имя файла 7280 1688 1040 10008 2718 a.exe"
инициализированная глобальная константная переменная -----> сегмент данных Нет, этот ответ неверен, вопрос был правильным для старых компоновщиков. Если раздел .rodata не связан с текстовым сегментом (Read + eXec) вместе с кодом, как это делали старые компоновщики, современный GNU ld по умолчанию связывает его с собственным сегментом, который доступен только для чтения и не исполняемый. Если не оптимизировать полностью, ненулевые глобальные константные переменные, конечно, не попадают в R+W раздел .data или не связываются с сегментом данных R+W. Вы правы в том, что в .bss помещаются единицы с нулевым значением.
В популярной архитектуре рабочего стола виртуальная память процесса делится на несколько сегментов:
Текстовый сегмент: содержит исполняемый код. Указатель инструкции принимает значения в этом диапазоне.
Сегмент данных: содержит глобальные переменные (т. е. объекты со статической связью). Подразделяются на данные только для чтения (например, строковые константы) и неинициализированные данные ("BSS").
Сегмент стека: содержит динамическую память для программы, т. е. свободное хранилище («кучу») и локальные кадры стека для всех потоков. Традиционно стек C и куча C росли в сегмент стека с противоположных концов, но я считаю, что от этой практики отказались, поскольку она слишком небезопасна.
Программа на C обычно помещает объекты со статической длительностью хранения в сегмент данных, динамически размещаемые объекты в свободное хранилище и автоматические объекты в стек вызовов потока, в котором они находятся.
На других платформах, таких как старый реальный режим x86 или встроенные устройства, все, очевидно, может быть радикально другим.
"Я считаю, что от этой практики отказались, потому что она слишком небезопасна" - и делает невозможным реализацию потоков, так как тогда нужно более одного стека на программу и они не могут быть все в конце :-)< /p>
@SteveJessop: Да, я тоже об этом подумал. Но потоки существуют уже давно — я не знаю, росли ли все стеки потоков также в обратном направлении или они росли бы как куча. так или иначе, в настоящее время все идет в том же направлении, и есть страницы защиты.
Я имею в виду эти переменные только с точки зрения C.
С точки зрения языка C все, что имеет значение, — это протяженность, объем, связь и доступ; именно то, как элементы отображаются в разные сегменты памяти, зависит от конкретной реализации, и это будет варьироваться. Стандарт языка не говорит о сегментах памяти вообще. Большинство современных архитектур действуют в основном одинаково; переменные блочной области и аргументы функций будут выделены из стека, файловая область и статические переменные будут выделены из сегмента данных или кода, динамическая память будет выделена из кучи, некоторые постоянные данные будут храниться в сегментах только для чтения и т. д.
Одна вещь, которую нужно помнить о хранилище, – правило как если бы. Компилятору не требуется размещать переменную в определенном месте — вместо этого он может разместить ее там, где ему заблагорассудится, пока скомпилированная программа ведет себя как если бы она выполнялась на абстрактной машине C в соответствии с правила абстрактной машины C. Это относится ко всем срокам хранения. Например:
- переменная, к которой нет доступа all, может быть полностью устранена - у нее нет места для хранения. в любом месте. Пример. Посмотрите, как в сгенерированном ассемблерном коде есть 42, но нет признаков 404.
- переменная с автоматической длительностью хранения, адрес которой не занят, вообще не нуждается в сохранении в памяти. Примером может служить переменная цикла.
- переменная, которая является константной или фактически константной, не обязательно должна находиться в памяти. Пример — компилятор может доказать, что foo фактически является константой, и встраивает ее использование в код. bar имеет внешнюю связь, и компилятор не может доказать, что он не будет изменен за пределами текущего модуля, поэтому он не встроен.
- объект, выделенный с помощью malloc, не обязательно должен находиться в памяти, выделенной из кучи! Пример — обратите внимание, что в коде нет вызова malloc, и значение 42 никогда не сохраняется в памяти, оно хранится в регистре!
- таким образом, объект, который был выделен с помощью malloc, и ссылка потеряна без освобождения объекта со свободной нет необходимости утечки памяти.
- объект, выделенный malloc, не обязательно должен находиться в куче ниже разрыва программы ( sbrk(0) ) в Unixen.
Нет, они могут быть в стеке или в сегменте данных. Они могут указывать куда угодно.
Не только в стеке или сегменте данных. Подумайте об указателе, который указывает на массив указателей. В этом случае указатели в массиве хранятся в куче.
- Переменные/автоматические переменные ---> раздел стека
- Динамически выделяемые переменные ---> раздел кучи
- Инициализированные глобальные переменные -> раздел данных
- Неинициализированные глобальные переменные -> раздел данных (bss)
- Статические переменные -> раздел данных
- Строковые константы -> раздел текста/раздел кода
- Функции -> раздел текста/раздел кода
- Код текста -> раздел текста/раздел кода
- Регистры -> Регистры процессора
- Ввод командной строки -> раздел среды/командной строки
- Переменные среды -> раздел среды/командной строки
Минимальные запускаемые примеры Linux с анализом дизассемблирования
Поскольку это детали реализации, не указанные в стандартах, давайте просто посмотрим, что делает компилятор в конкретной реализации.
В этом ответе я либо приведу ссылки на конкретные ответы, в которых проводится анализ, либо приведу анализ непосредственно здесь, а здесь обобщу все результаты.
Все они есть в разных версиях Ubuntu/GCC, и результаты, вероятно, довольно стабильны в разных версиях, но если мы обнаружим какие-либо различия, давайте укажем более точные версии.
Локальная переменная внутри функции
Будь то главная или любая другая функция:
- -O0 : стек
- -O3 : регистрирует, если они не разливаются, в противном случае складываются
Глобальные переменные и переменные статических функций
- если инициализировано значением 0 или не инициализировано (и, следовательно, неявно инициализировано значением 0 ): раздел .bss, см. также: Почему требуется сегмент .bss?
- иначе: раздел .data
char * и char c[]
TODO будут ли также помещаться в стек очень большие строковые литералы? Или .данные? Или компиляция не работает?
Аргументы функции
Затем, как показано в разделе Что означает в gdb?, -O0 сбрасывает все в стек, а -O3 пытается максимально использовать регистры.
Однако, если функция встроена, они обрабатываются так же, как обычные локальные переменные.
константа
Я считаю, что это не имеет значения, потому что вы можете привести его к типу.
И наоборот, если компилятор может определить, что некоторые данные никогда не записываются, он теоретически может поместить их в .rodata, даже если они не являются константами.
Указатели
Это переменные (содержащие адреса, то есть числа), как и все остальное :-)
маллок
Вопрос не имеет особого смысла для malloc, так как malloc — это функция, и в:
*i — это переменная, содержащая адрес, поэтому она соответствует описанному выше случаю.
Что касается того, как malloc работает внутри, когда вы вызываете его, ядро Linux помечает определенные адреса как доступные для записи в своих внутренних структурах данных, и когда программа первоначально касается их, происходит ошибка, и ядро включает таблицы страниц, которые позволяет осуществлять доступ без segfaul: Как работает пейджинг x86?
Обратите внимание, однако, что системный вызов exec делает то же самое, когда вы пытаетесь запустить исполняемый файл: он помечает страницы, которые он хочет загрузить, и записывает туда программу. См. также: Как ядро получает исполняемый файл бинарный файл работает под linux? За исключением того, что у exec есть некоторые дополнительные ограничения на то, куда загружать (например, код нельзя перемещать).
Точный системный вызов, используемый для malloc, — это mmap в современных реализациях 2020, а в прошлом использовался brk: использует ли malloc() brk() или mmap()?
Теперь мы обратим внимание на наблюдение, сделанное в начале главы: C++ может создавать объекты двумя различными способами (см. рис. 4), тогда как Java может делать это только одним способом. Программа C++ выделяет память для хранения объекта в зависимости от того, как программа создает объект. Наша следующая задача — понять, как программа организует свою память и управляет ею.
"Распределять" означает назначать, распределять, распределять или "отделять для определенной цели". Программы управляют своей памятью, разбивая или разделяя ее на разные блоки, выполняющие определенные задачи. Двумя из этих единиц являются стек и куча, которые управляют неиспользуемой памятью программы и выделяют ее для различных типов данных или переменных. Когда программе больше не нужна память, она может освободить ее. Освобожденная память возвращается к своему источнику, стеку или куче, и становится доступной для повторного использования.
Когда операционная система (ОС) запускает программу, она сначала загружает программу в основную память. Память используется как для машинных инструкций программы, так и для данных, которые использует программа. Когда я создавал рисунок 1, компьютеры обычно использовали технику выделения памяти, называемую сегментированной памятью. Когда ОС загружала и запускала программу на компьютере с сегментированной памятью, она выделяла для программы непрерывный блок или сегмент памяти. Программа разделяла свою память на области, которые выполняли определенные программные функции. Хотя этот метод управления памятью уже устарел и был заменен страничной памятью, программы продолжают организовывать свою память на основе показанных здесь функциональных блоков.
Компьютеры со страничной памятью динамически управляют памятью, поэтому объем памяти, выделенный программе, может увеличиваться и уменьшаться по мере изменения потребностей программы. Память выделяется программе и освобождается операционной системой в виде блоков фиксированного размера, называемых страницами. Когда ОС загружает программу на компьютер со страничной памятью, она первоначально выделяет минимальное количество страниц для программы и выделяет дополнительную память по мере необходимости. Машинный код и данные, которые не нужны немедленно, не загружаются, а страницы, хранящие машинный код и данные, которые не использовались в последнее время, могут быть возвращены в ОС. Хотя на рис. 1 больше не представлена физическая схема памяти, она точно представляет функциональную или логическую организацию памяти программ.
- Текстовая область содержит машинные инструкции программы (т. е. исполняемый код). переменные определяются в глобальной области видимости вне какой-либо функции или объекта; статические переменные имеют ключевое слово static, включенное как часть их определения. Память, содержащая глобальные и статические переменные, обычно выделяется при запуске программы.
- Пространство, показанное здесь, было выделено, но не использовалось в системе с сегментированной памятью и предоставляло пространство, в котором могли расти стек и куча. Это пространство не размещается в системе со страничной памятью, а означает пространство, доступное для увеличения стека и кучи.
- Стек (иногда называемый стеком времени выполнения) содержит все автоматические (т. е. нестатические) переменные.
- Память выделяется из кучи и возвращается в нее с помощью операторов new и delete соответственно.
При обсуждении программы на C++ мы используем термин "распределить" двумя разными способами. Во-первых, операционные системы отвечают за управление всеми ресурсами компьютера, включая оперативную память. ОС выделяет физическую память работающей программе в страницах, но эта операция полностью прозрачна для программистов и неподконтрольна им.
С другой стороны, запущенные программы могут выделять память для программных данных. Система компилятора C++ включает подсистему управления памятью в каждой программе C++. Он выделяет память для автоматических переменных в стеке и динамических переменных, созданных с помощью оператора new, в куче.
Когда программа освобождает память, система управления памятью возвращает ее в исходное состояние, либо в стек, либо в кучу.
Из рисунка 1 видно, что работающая программа хранит свои данные в одной из трех логических областей памяти. ОС выделяет память для глобальных и статических переменных, когда загружает программу в память, и не освобождает ее до тех пор, пока программа не завершится. Значения, хранящиеся в этих переменных, не изменяются, если только программа не изменяет их явно (за исключением изменений, сделанных внешними - вне программы - системами). Две другие области, стек и куча, более динамичны — память выделяется и освобождается программой по мере необходимости. Различия между этими двумя областями заключаются в алгоритмах управления памятью и, следовательно, в их поведении.
Стек
Стек — это простая структура данных по принципу "последним пришел — первым ушел" (LIFO). Представление стопки тарелок в столовой обычно знакомит начинающих компьютерных ученых со стопками. В примере со столовой тарелки удаляются или добавляются в стопку только сверху. Одним из наших первых действий при входе в кафетерий является снять тарелку с вершины стопки тарелок, прежде чем мы пройдем через очередь. Точно так же посудомоечные машины толкают каждую чистую тарелку на вершину стопки по одной. Таким образом, последняя чистая тарелка, помещенная в стопку, становится первой тарелкой, которую покупатель снимает с верха. Вставка или извлечение тарелки из середины стопки не допускается. Стеки должны поддерживать как минимум две операции: push и pop; другие операции возможны, но не обязательны.
- Предметы (например, тарелки), которые вставляются в стопку и выпадают из нее. Элементы извлекаются в порядке, обратном тому, в котором они помещались в стек.
- На самом деле ничто не перемещается физически, когда элементы данных (переменные или объекты) помещаются в стек в памяти или извлекаются из него. Изменяются только значения, хранящиеся в памяти, управляемой стеком, что и пытается проиллюстрировать эта версия стека. Можно и часто смешивать операции push и pop.
В обеих анимациях на рис. 2 стеки упрощены, поскольку показано, что все элементы, хранящиеся в стеке, имеют одинаковый размер. Элементы данных, помещаемые в стек среды выполнения, могут быть любого удобного размера. Тем не менее, стеки несколько жесткие в том смысле, что доступ к ним возможен только сверху. Но эта жесткость также упрощает реализацию стеков и делает операции push и pop быстрыми и эффективными.
Напротив, куча более гибкая, чем стек. В то время как стек позволяет выделять и освобождать память только вверху, программы могут выделять или освобождать память в любом месте кучи. Итак, программа должна возвращать память в стек в порядке, обратном ее выделению. Но программа может возвращать память в кучу в любом порядке. Это означает, что в середине стека может быть «дыра» — нераспределенная память, окруженная выделенной памятью. Чтобы увидеть разницу, сравните рисунки 2 и 3.
Демонстрация поведения кучи. Куча выделяет память, находя и возвращая первый блок памяти, достаточно большой для удовлетворения запроса. Память возвращается или освобождается в любом удобном порядке. Когда программа освобождает или освобождает два соседних блока памяти, куча объединяет их в один блок. Это позволяет куче лучше удовлетворять будущие потребности в больших блоках памяти. Заштрихованный блок иллюстрирует запрос большого блока (в два раза больше окрашенных блоков) памяти.
Существует только одно ограничение на память, выделяемую программе из кучи: она должна формировать непрерывный блок, достаточно большой, чтобы удовлетворить запрос с помощью одного фрагмента памяти.Это единственное ограничение увеличивает сложность кучи, по крайней мере, двумя способами: во-первых, код, выполняющий операцию выделения памяти, должен сканировать кучу, пока не найдет непрерывный блок памяти, достаточно большой для удовлетворения запроса. Во-вторых, когда память возвращается в стек, смежные освобожденные блоки должны быть объединены, чтобы лучше обрабатывать будущие запросы на большие блоки памяти. Повышенная сложность кучи означает, что управление памятью с кучей происходит медленнее, чем со стеком. Но куча также имеет преимущества, которые оправдывают увеличение накладных расходов. В следующем разделе рассматриваются эти преимущества и показано, как стек и куча работают вместе для управления сложными данными в работающей программе.
Типичная структура памяти запущенного процесса
1. Текстовый сегмент:
Текстовый сегмент, также известный как сегмент кода или просто текст, представляет собой один из разделов программы в объектном файле или в памяти, который содержит исполняемые инструкции.
Как память. области текстовый сегмент может быть помещен ниже кучи или стека, чтобы предотвратить перезапись кучи и переполнения стека.
Обычно текстовый сегмент является общим, поэтому для часто выполняемых программ, таких как текстовые редакторы, компилятор C, оболочки и т. д., в памяти должна находиться только одна копия. Кроме того, текстовый сегмент часто доступен только для чтения, чтобы программа не могла случайно изменить свои инструкции.
<р>2. Инициализированный сегмент данных:Инициализированный сегмент данных, обычно называемый просто сегментом данных. Сегмент данных — это часть виртуального адресного пространства программы, которая содержит глобальные переменные и статические переменные, инициализируемые программистом.
Обратите внимание, что сегмент данных не доступен только для чтения, так как значения переменные могут быть изменены во время выполнения.
Этот сегмент можно далее разделить на инициализированную область только для чтения и инициализированную область чтения-записи.
Например, глобальная строка, определяемая char s[] = «hello world» в C, и оператор C, такой как int debug=1 вне основного (т.е. глобального), будет храниться в инициализированной области чтения-записи. А глобальный оператор C, такой как const char* string = «hello world», сохраняет строковый литерал «hello world» в инициализированной области только для чтения, а строку переменной указателя символа — в инициализированной области чтения-записи.
Пример: статический int i = 10 будет храниться в сегменте данных, а глобальный int i = 10 также будет храниться в сегменте данных <р>3. Сегмент неинициализированных данных:
Неинициализированный сегмент данных, часто называемый сегментом «bss», в честь древнего оператора ассемблера, означавшего «блок, начинающийся с символа». Данные в этом сегменте инициализируются ядром до арифметического 0 перед началом выполнения программы
неинициализированные данные начинаются в конце сегмента данных и содержат все глобальные переменные и статические переменные, которые инициализируются нулем или не имеют явной инициализации в исходном коде.
Например, переменная, объявленная как static int i; будет содержаться в сегменте BSS.
Например, глобальная переменная, объявленная int j; будет содержаться в сегменте BSS. <р>4. Стек:
Область стека традиционно примыкала к области кучи и росла в противоположном направлении; когда указатель стека встречался с указателем кучи, свободная память была исчерпана. (С современными большими адресными пространствами и методами виртуальной памяти они могут быть размещены практически где угодно, но обычно они растут в противоположных направлениях.)
Область стека содержит программный стек, структуру LIFO, обычно расположенную в верхних частях Память. В стандартной компьютерной архитектуре PC x86 он увеличивается до нулевого адреса; на некоторых других архитектурах он растет в противоположном направлении. Регистр «указатель стека» отслеживает вершину стека; он корректируется каждый раз, когда значение «помещается» в стек. Набор значений, передаваемых для одного вызова функции, называется «фреймом стека»; Фрейм стека состоит как минимум из адреса возврата.
Стек, в котором хранятся автоматические переменные вместе с информацией, сохраняемой при каждом вызове функции. Каждый раз, когда вызывается функция, в стеке сохраняется адрес возврата и определенная информация о среде вызывающего объекта, например, некоторые регистры машины. Затем вновь вызванная функция выделяет место в стеке для своих автоматических и временных переменных. Вот как могут работать рекурсивные функции в C. Каждый раз, когда рекурсивная функция вызывает сама себя, используется новый кадр стека, поэтому один набор переменных не пересекается с переменными из другого экземпляра функции. <р>5. Куча:
Куча — это сегмент, в котором обычно происходит динамическое выделение памяти.
Область кучи начинается в конце сегмента BSS и оттуда увеличивается до более крупных адресов.Область кучи управляется функциями malloc, realloc и free, которые могут использовать системные вызовы brk и sbrk для настройки своего размера (обратите внимание, что использование brk/sbrk и одной «области кучи» не требуется для выполнения контракта malloc/realloc/free; они также могут быть реализованы с использованием mmap для резервирования потенциально несмежных областей виртуальной памяти в виртуальном адресном пространстве процесса). Область кучи совместно используется всеми общими библиотеками и динамически загружаемыми модулями в процессе.
Примеры.
Команда size(1) сообщает размеры (в байтах) текста, данных и сегментов bss. (для более подробной информации обратитесь к справочной странице size(1))
Настольный компьютер Джудит работает медленно, и почти вся его память используется, даже когда она не запускает никаких приложений. Что может быть не так?
Последние версии Windows пытаются заполнить память вашего ПК: программа SuperFetch ищет любую свободную память и что-то загружает в нее. Фото: Creativeact - Бизнес-серия //Alamy
Последние версии Windows пытаются заполнить память вашего ПК: программа SuperFetch ищет любую свободную память и что-то загружает в нее. Фото: Creativeact - Бизнес-серия //Alamy
У меня четырехлетний рабочий стол Windows, который часто работает очень медленно, а диспетчер задач показывает, что используется 80–90 % физической памяти, даже когда я не запускаю никаких приложений. Виновником, по-видимому, является Svchost.exe, а иногда и RapportService.exe *32. Я провел чистку программного обеспечения, как предлагалось в вашей колонке, но это не помогло.
Мой компьютер — это настольный компьютер HP CQ5307UK с процессором AMD Athlon II X3 435 с тактовой частотой 2,90 ГГц и 3 ГБ памяти, работающий под управлением Microsoft Windows 7 и Norton Internet Security. Я использую Microsoft Office Pro и Mailwasher. Юдит
Современные версии Windows — те, что последовали за Windows XP, — предназначены для использования всей физической памяти вашего ПК: для этого она и предназначена. В любом случае 3 ГБ памяти плюс файл подкачки объемом 4 ГБ (скрытый файл с именем pagefile.sys) более чем достаточен для используемого вами программного обеспечения.
Windows может работать медленно из-за утечки памяти из-за программы или драйвера устройства, из-за того, что у вас недостаточно места на диске, из-за того, что мошеннический процесс загружает ваш процессор почти на 100 %, из-за перегрева вашего ПК или из-за того, что вируса или другого вредоносного ПО.
Поскольку вы спросили об использовании памяти, я сосредоточусь на этом. Однако убедитесь, что у вас есть как минимум 5 ГБ свободного места на жестком диске на случай, если Windows потребуется расширить свой файл подкачки. Кроме того, запустите быстрое сканирование с помощью бесплатного антивируса Malwarebytes Anti-Malware (MBAM) в качестве разовой проверки, чтобы убедиться, что Norton ничего не упустило.
Свободная память
Диспетчер задач Windows не является надежным показателем объема свободной памяти. К счастью, в Windows 7 есть системный монитор. Вы можете найти PerfMon, введя pe или perf в поле запуска в нижней части меню «Пуск». Запустив его, нажмите «Монитор ресурсов», чтобы получить показанный ниже результат.
Еще лучшим руководством является бесплатная RAMMap Марка Руссиновича, которую можно загрузить из раздела Windows Sysinternals на веб-сайте Microsoft. (Инструменты Руссиновича были настолько хороши, что Microsoft купила компанию.)
Как уже упоминалось, последние версии Windows пытаются заполнить память вашего ПК: программа SuperFetch ищет любую свободную память и что-то загружает в нее. SuperFetch знает, какие программы вы используете, и автоматически предварительно загружает их. Гораздо быстрее запускать данные из памяти, чем извлекать их с жесткого диска.
Поэтому сложно ответить на вопрос, сколько «свободной» памяти у вас есть в любой момент времени. Однако PerfMon и RAMMap дают разумный ответ в виде «Доступной памяти».
Фото: снимок экрана
В показанном здесь примере у меня используется около 2 ГБ и доступно более 800 МБ. На этом ПК установлены Firefox, Chrome и Internet Explorer, а также Microsoft Word, PerfMon, RAMMap и карточная игра Freecell.
Перезагрузите компьютер и посмотрите, сколько памяти доступно. Не запускайте ничего другого в течение 15-30 минут, чтобы посмотреть, не изменится ли что-то: у вас может быть "утечка памяти" (т. е. программа продолжает занимать больше памяти и не отдавать ее обратно).
После этого загружайте свои программы по одной, чтобы посмотреть, сколько памяти занимает каждая из них и не тормозит ли ваш ПК. Если программа создает проблему, удалите ее. Если вы не можете обойтись без него, переустановите его и надейтесь, что он будет себя вести в будущем.
Память по страницам
PerfMon показывает, что Windows использует страницы памяти разными способами. Основные из них: «Активная» (т.е. работающие программы), «Измененная», «Резервная» и «Свободная память». RAMMap предоставляет более полную картину, включая обнуленную память и показывая, сколько памяти используется для различных целей.
По сути, большая часть памяти свободна, если только она не используется активно. Если Windows требуется больше памяти, она может мгновенно использовать обнуленные страницы: они пусты. После этого он может мгновенно использовать резервные страницы, которые могли быть загружены SuperFetch или оставлены после закрытия программы. (Эти страницы не обнуляются, поэтому, если вы перезапустите программу, она загрузится очень быстро. Но их не нужно сохранять.) Далее Windows может использовать Измененные страницы, предварительно сохранив их. Необходимость записи данных на диск замедляет процесс, поэтому эта память не указывается в списке доступной памяти. Однако он по-прежнему доступен, если вам это нужно.
Нужно больше? Windows может начать «обрезать» страницы, которые программы зарезервировали для активного использования. Он может решить использовать эту память для более срочных целей.
Часть памяти недоступна. Существуют таблицы страниц (индекс страниц памяти Windows), «невыгружаемый пул» (страницы, которые нельзя сохранить на диск и которые должны оставаться в ОЗУ), память, заблокированная драйвером (вероятно, заблокированная виртуальной машиной, такой как Hyper-V или VMware) и AWE (обычно памятью управляет SQL Server).
На моем пятилетнем ноутбуке под управлением Windows 7 размер таблицы страниц составляет 37 МБ, невыгружаемого пула — 180 МБ, а размер заблокированного драйвера — 42 МБ. ПК явно различаются. Однако большие значения могут указывать на проблемы, снижающие производительность Windows.
Вы можете использовать RAMMap для сохранения и сравнения снимков. Например, вы можете сделать снимок памяти, когда ваш компьютер работает хорошо, и сравнить его с тем, когда он работает медленно.
Проблемное ПО
Вы упоминаете Svchost.exe и RapportService.exe *32 как программы, потребляющие много ресурсов. Svchost.exe — это сокращение от «хост службы», и на вашем компьютере запущено несколько экземпляров svchost для размещения различных служб. Если вы загрузите и запустите Process Explorer от Sysinternals — еще один инструмент Руссиновича и хорошую замену диспетчеру задач — он должен показать множество svchosts (возможно, восемь или 10) и различные службы Windows, которые они запускают.
Если конкретный экземпляр svchost неоднократно нарушал правила, поищите справку о службах, которые он размещает. Иногда вы можете восстановить службы через Центр обновления Windows или обновление системы или изменить способ их работы. Введите local в поле запуска и выберите «Просмотреть локальные службы», чтобы увидеть, какие из них работают на вашем компьютере и запускаются ли они автоматически.
RapportService.exe *32 поставляется компанией Trusteer, компанией IBM, и обычно устанавливается вместе с банковским программным обеспечением. Rapport — это небольшая программа, которая не должна влиять на ваш процессор или оперативную память. Если вы не пользуетесь интернет-банком, вы можете удалить его.
Имена svchost.exe и RapportService.exe могут использоваться вредоносными программами для сокрытия своих гнусных целей, поэтому не забудьте запустить MBAM.
Служба индексирования Windows, которую можно отключить, и Norton также могут замедлять работу ПК.
Обновить или обновить?
Всегда лучше иметь больше памяти. К сожалению, ваш HP/Compaq позволяет использовать только 4 ГБ, поэтому расширение с 3 ГБ — неэкономичный вариант.
Согласно HP, вы также можете обновить AMD Athlon II X3 435 (Passmark 2496), но ни одна из альтернатив Phenom II не выглядит достаточно быстрой, чтобы оправдать затраты или усилия.
В этом случае вам придется искать неисправное программное обеспечение, мошеннический процесс или драйвер с утечкой, которые замедляют работу вашего ПК, или пробовать альтернативные решения. Одним из них было бы обновить все ваши драйверы. Другой вариант — использовать раздел восстановления ПК (я полагаю, что он есть) для обновления или переустановки Windows 7. Это не очень весело со старой системой, потому что Центру обновления Windows придется переустанавливать исправления четырехлетней давности. Судя по моему опыту, это должно пройти гладко, но требует около дюжины перезапусков в течение двух-трех дней.
Недостаток заключается в том, что вам также придется переустанавливать все свои приложения и восстанавливать резервные копии данных.
Если вы это сделаете, сначала сделайте полную резервную копию жесткого диска, чтобы вы могли восстановить свой компьютер до его текущего состояния, если что-то пойдет не так. А когда вы закончите, сделайте еще одну полную резервную копию жесткого диска, чтобы вам никогда не пришлось повторять весь процесс.
Читайте также: