Programowanie w systemie UNIX/Memory

Limity

edytuj

Sprawdzamy limity [1] za pomocą komendy Basha:[2]

ulimit -a

Przykładowy wynik:

 core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 126505
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 126505
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Pamięć a programowanie

edytuj

W uproszczeniu z punktu widzenia programisty pamięć[3][4] jest podzielona na:[5][6]

  • stos (ang. stack)[7]
  • sterta, kopiec lub stóg (ang. heap)[8]


Porównanie rodzajów pamięci
alokacja wielkość zmiana wielkości ogranicznie wielkości dostęp zmienne funkcje
sterta dynamiczna duża możliwa pamięć fizyczna RAM globalne i dynamiczne malloc/free
stos statyczna mała niemożliwa wielkość stosu = ulimit -s = 8192 kB LIFO lokalne

Błędne wykorzystanie pamięci powoduje:[9]

  • Przepełnienie bufora[10]
    • przepełnienie bufora stosu[11]
  • przepełnienie sterty
  • wycieki pamięci (wykrywanie za pomocą Valgrinda)[12]

i może powodować zagrożenia informatyczne [13]

Porządek bajtów i bitów (ang. byto order = endianess)

edytuj

Wiesz zapewne, że podstawową jednostką danych jest bit, który może mieć wartość 0 lub 1. Kilka kolejnych bitów[14] stanowi bajt (dla skupienia uwagi, przyjmijmy, że bajt składa się z 8 bitów). Często typ short ma wielkość dwóch bajtów i wówczas pojawia się pytanie w jaki sposób są one zapisane w pamięci - czy najpierw ten bardziej znaczący - big-endian, czy najpierw ten mniej znaczący - little-endian.[15]

Skąd takie nazwy? Otóż pochodzą one z książki Podróże Guliwera, w której liliputy kłóciły się o stronę, od której należy rozbijać jajko na twardo. Jedni uważali, że trzeba je rozbijać od grubszego końca (big-endian) a drudzy, że od cieńszego (little-endian). Nazwy te są o tyle trafne, że w wypadku procesorów wybór kolejności bajtów jest sprawą czysto polityczną, która jest technicznie neutralna.

Sprawa się jeszcze bardziej komplikuje w przypadku typów, które składają się np. z 4 bajtów. Wówczas są aż 24 (4 silnia) sposoby zapisania kolejnych fragmentów takiego typu. W praktyce zapewne spotkasz się jedynie z kolejnościami big-endian lub little-endian, co nie zmienia faktu, że inne możliwości także istnieją i przy pisaniu programów, które mają być przenośne należy to brać pod uwagę.

Poniższy przykład dobrze obrazuje oba sposoby przechowywania zawartości zmiennych w pamięci komputera (przyjmujemy CHAR_BIT == 8 oraz sizeof(long) == 4, bez bitów wypełnienia (ang. padding bits)): unsigned long zmienna = 0x01020304; w pamięci komputera będzie przechowywana tak:

adres         | 0  | 1  | 2  | 3  |
big-endian    |0x01|0x02|0x03|0x04|
little-endian |0x04|0x03|0x02|0x01|

Zobacz:

Źródła

edytuj
  1. Size limit of an Array in gcc
  2. ulimit - opis
  3. Anatomy of a Program in Memory by Gustavo Duarte Jan 27th, 2009
  4. What Every Programmer Should Know About Memory by Ulrich Drepper
  5. management in C: The heap and the stack by Leo Ferres
  6. Layout of C Programs
  7. Stos w wikipedii
  8. Kopiec w wikipedii
  9. Bezpieczeństwo pamięci w ang. wikipedii
  10. Przepełnienie bufora
  11. Epilogues, Canaries, and Buffer Overflows by Gustavo Duarte Mar 19th, 2014
  12. Użycie Valgrinda do wykrywania wycieków pamięci
  13. Bezpieczeństwo teleinformatyczne
  14. Standard wymaga aby było ich co najmniej 8 i liczba bitów w bajcie w konkretnej implementacji jest określona przez makro CHAR_BIT zdefiniowane w pliku nagłówkowym limits.h
  15. betterexplained article: a-little-diddy-about-binary-file-formats