Чтение онлайн

на главную - закладки

Жанры

Основы программирования в Linux
Шрифт:

В итоге, когда приложение исчерпает и физическую память, и область свопинга или когда она превысит максимальный размер стека, ядро откажется выполнить запрос на дальнейшее выделение памяти, может завершить программу и выгрузить ее.

Примечание

Это поведение, сопровождающееся уничтожением процесса, отличается от поведения более старых версий Linux и множества других вариантов UNIX, в которых просто аварийно завершалась функция

malloc
. Называется оно уничтожением из-за нехватки памяти (out of memory (OOM) killer), и хотя может показаться чересчур радикальным,
на самом деле служит разумным компромиссом между возможностью быстрого и эффективного выделения памяти процессам и необходимостью собственной защиты ядра от полного исчерпания ресурсов, что является серьезной проблемой.

Но что это означает для прикладного программиста? В основном благую весть. Система Linux очень умело управляет памятью и позволяет приложениям использовать большие области памяти и даже очень большие единые блоки памяти. Но вы должны помнить о том, что выделение двух блоков памяти в результате не приведет к формированию одного непрерывно адресуемого блока памяти. Вы получите то, что просили: два отдельных блока памяти.

Означает ли этот, по-видимому, неограниченный источник памяти с последующим прерыванием и уничтожением процесса, что в проверке результата, возвращаемого функцией

malloc
, нет смысла? Конечно же нет. Одна из самых распространенных проблем в программах на языке С, использующих динамическую память, — запись за пределами выделенного блока. Когда это происходит, программа может не завершиться немедленно, но вы, вероятно, перезапишите некоторые внутренние данные, используемые подпрограммами библиотеки malloc.

Обычный результат — аварийное завершение последующих вызовов

malloc
не из- за нехватки памяти, а из-за повреждения структур памяти. Такие проблемы бывает трудно отследить, и чем быстрее в программах обнаружится ошибка, тем больше шансов найти причину. В главе 10, посвященной отладке и оптимизации, мы обсудим некоторые средства, которые могут помочь вам выявить проблемы, связанные с памятью.

Неправильное обращение к памяти

Предположим, что вы хотите сделать что-то "плохое" с памятью. В упражнении 7.4 в программе memory4.c вы выделяете некоторую область памяти, а затем пытаетесь записать данные за пределами выделенной области.

Упражнение 7.4. Неправильное обращение к вашей памяти

#include <stdlib.h>

#define ONE_K (1024)

int main {

 char *some_memory;

 char *scan_ptr;

 some_memory = (char *)malloc(ONE_K);

 if (some_memory == NULL) exit(EXIT_FAILURE);

 scan_ptr = some_memory;

 while (1) {

*scan_ptr = '\0';

scan_ptr++;

 }

 exit(EXIT_SUCCESS);

}

Вывод прост:

$ ./memory4

Segmentation fault

Как

это работает

Система управления памятью в ОС Linux защищает остальную систему от подобного некорректного использования памяти. Для того чтобы быть уверенной в том, что одна плохо ведущая себя программа (как эта) не сможет повредить любые другие программы, система Linux прекратила ее выполнение.

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

Указатель null

Современные системы Linux, в отличие от ОС MS-DOS, но подобно новейшим вариантам ОС Windows, надежно защищены от записи или чтения по адресу, на который ссылается пустой указатель (

null
), хотя реальное поведение системы зависит от конкретной реализации.

Выполните упражнение 7.5.

Упражнение 7.5. Обращение по указателю
null

Давайте выясним, что произойдет, когда мы попытаемся обратиться к памяти по пустому или null-указателю в программе memory5a.c.

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

int main {

 char *some_memory = (char*)0;

 printf("A read from null %s\n", some_memory);

 sprintf(some_memory, "A write to null\n");

 exit(EXIT_SUCCESS);

}

Будет получен следующий вывод:

$ ./memory5a

A read from null (null)

Segmentation fault

Как это работает

Первая функция

printf
пытается вывести строку, полученную от указателя
null
; далее
sprintf
пытается записать по указателю
null
. В данном случае Linux (под видом библиотеки GNU С) простила чтение и просто предоставила "магическую" строку, содержащую символы
(null)\0
. Система не столь терпима в случае записи и просто завершила программу. Такое поведение порой полезно при выявлении программных ошибок.

Если вы повторите попытку, но не будете использовать библиотеку GNU С, вы обнаружите, что безадресное чтение не разрешено. Далее приведена программа memory5b.c:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

int main {

 char z = *(const char *)0;

 printf("I read from location zero\n");

 exit(EXIT_SUCCESS);

Поделиться:
Популярные книги

Личный аптекарь императора

Карелин Сергей Витальевич
1. Личный аптекарь императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Личный аптекарь императора

Диверсант

Вайс Александр
2. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Диверсант

Воронцов. Перезагрузка

Тарасов Ник
1. Воронцов. Перезагрузка
Фантастика:
попаданцы
альтернативная история
фантастика: прочее
5.00
рейтинг книги
Воронцов. Перезагрузка

Локки 9. Потомок бога

Решетов Евгений Валерьевич
9. Локки
Фантастика:
фэнтези
попаданцы
героическая фантастика
боевая фантастика
5.00
рейтинг книги
Локки 9. Потомок бога

Рассвет русского царства

Грехов Тимофей
1. Новая Русь
Документальная литература:
историческая литература
5.00
рейтинг книги
Рассвет русского царства

Сирийский рубеж 3

Дорин Михаил
7. Рубеж
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сирийский рубеж 3

На границе империй. Том 7. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
На границе империй. Том 7. Часть 4

Локки 11. Потомок бога

Решетов Евгений Валерьевич
11. Локки
Фантастика:
героическая фантастика
боевая фантастика
фэнтези
юмористическое фэнтези
5.00
рейтинг книги
Локки 11. Потомок бога

Наследник Теней

Лазарь
3. Хозяин Теней
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Наследник Теней

Наследие Маозари 4

Панежин Евгений
4. Наследие Маозари
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Наследие Маозари 4

Личник

Валериев Игорь
3. Ермак
Фантастика:
альтернативная история
6.33
рейтинг книги
Личник

Последний Паладин. Том 3

Саваровский Роман
3. Путь Паладина
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 3

Вечный. Книга VI

Рокотов Алексей
6. Вечный
Фантастика:
рпг
фэнтези
5.00
рейтинг книги
Вечный. Книга VI

Вперед в прошлое 9

Ратманов Денис
9. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 9