GNU/Linux >> Znalost Linux >  >> Linux

Procesy Linux – funkce rozvržení paměti, exit a _exit C

V 1. části série článků o linuxových procesech rozvíjíme znalosti o linuxových procesech diskusí o funkci main() a funkcích jazyka C souvisejících s prostředím.

V tomto článku se budeme zabývat rozložením paměti procesu a procesem ukončujícím funkce C.

Linux Processes Series:část 1, část 2 (tento článek), část 3

Rozložení paměti procesu

Rozložení paměti procesu v Linuxu může být velmi komplikované, pokud se pokusíme vše podrobně představit a popsat. Zde tedy představíme pouze věci, které mají významný význam.

Pokud se pokusíme vizualizovat rozložení paměti procesu, máme něco takového:

Pojďme si vysvětlit jednotlivé komponenty výše uvedeného rozložení jednu po druhé:

  • Argumenty příkazového řádku a proměnné prostředí jsou uloženy v horní části rozložení paměti procesu na vyšších adresách.
  • Poté přichází segment zásobníku. Toto je paměťová oblast, kterou proces používá k ukládání lokálních proměnných funkcí a dalších informací, které se ukládají při každém volání funkce. Tyto další informace zahrnují zpáteční adresu, tj. adresu, odkud byla funkce volána, některé informace o prostředí volajících, jako jsou registry strojů atd., jsou uloženy v zásobníku. Zde také stojí za zmínku, že pokaždé, když je rekurzivní funkce nazývána, je vygenerován nový zásobníkový rámec, takže každá sada lokálních proměnných nezasahuje do žádné jiné sady.
  • Segment haldy je ten, který se používá pro dynamické přidělování paměti. Tento segment není omezen na jeden proces, místo toho je sdílený mezi všemi procesy běžícími v systému. Jakýkoli proces by mohl dynamicky alokovat paměť z tohoto segmentu. Vzhledem k tomu, že tento segment je sdílen napříč procesy, měla by být paměť z tohoto segmentu používána obezřetně a měla by být uvolněna, jakmile je proces pomocí této paměti dokončen.
  • Jak se zdá z obrázku výše, hromada roste směrem dolů, zatímco hromada roste nahoru.
  • Všechny globální proměnné, které nejsou inicializovány v programu, jsou uloženy v segmentu BSS. Po provedení jsou všechny neinicializované globální proměnné inicializovány s hodnotou nula. Všimněte si, že BSS znamená „Block Started by Symbol“.
  • Všechny inicializované globální proměnné jsou uloženy v datovém segmentu.
  • Textový segment je oblast paměti, která obsahuje strojové instrukce, které CPU provádí. Obvykle je tento segment sdílen mezi různými instancemi stejného prováděného programu. Protože nemá smysl měnit instrukce CPU, má tento segment oprávnění pouze pro čtení.

Upozorňujeme, že výše uvedený obrázek je pouze logickým znázorněním rozložení paměti. Neexistuje žádná záruka, že na daném systému bude paměťové rozložení procesu vypadat takto. Kromě toho existuje několik dalších segmentů pro tabulku symbolů, informace o ladění atd.

Funkce pro ukončení procesu exit() a _exit()

Následující funkce mohou způsobit ukončení procesu:

  1.  ukončit (stav) (stejné jako stav návratu )
  2.  _exit(status) nebo _Exit(status)

Rozdíl mezi funkcí exit() a funkcí _exit() je v tom, že funkce exit() a funkce _exit() podporují určité vyčištění, než vrátí řízení zpět jádru, zatímco ostatní dvě funkce se okamžitě vrátí do jádra.

Funkce _exit je specifikována POSIX, zatímco _Exit je specifikována ISO C. Kromě toho mezi nimi není žádný jiný zásadní rozdíl.

Jak již bylo uvedeno výše, vyčištění je hlavním rozdílem mezi exit() a _exit(). Než to prakticky dokážeme, pojďme pochopit další funkci ‚atexit()‘.

Následuje prototyp:

int atexit(void (*function)(void));

Jak název napovídá, jedná se o systémové volání, které vezme ukazatel funkce a zaregistruje tuto konkrétní funkci jako funkci čištění pro tento program. To znamená, že registrovaná funkce je volána vždy, když se proces normálně ukončí a ukončení procesu podporuje vyčištění.

Pokud si ještě jednou projdete poslední řádek výše uvedeného odstavce, uvidíte, že funkce ‚atexit‘ je součástí procesu čištění, který rozlišuje mezi funkcemi exit() a _exit(). Zde je kód, který používá funkce atexit() a exit()..

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

extern char **environ;

void exitfunc(void)
{
  printf("\n Clean-up function called\n");
}

int main(int argc, char *argv[])
{
  int count = 0;

  atexit(exitfunc);

  printf("\n");
  while(environ[count++] != NULL)
  {
    // Dos some stuff
  }

  exit(0);
}

Ve výše uvedeném kódu je funkce ‚exitfunc()‘ zaregistrována do jádra jako funkce čištění pomocí funkce atexit().

Při spuštění výše uvedeného kódu:

$ ./environ

Clean-up function called

Vidíme, že byla zavolána funkce čištění.

POKUD změníme volání z exit() ve výše uvedeném kódu na _exit() :

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

extern char **environ;

void exitfunc(void)
{
  printf("\n Clean-up function called\n");
}

int main(int argc, char *argv[])
{
  int count = 0;

  atexit(exitfunc);

  printf("\n");
  while(environ[count++] != NULL)
  {
    // Dos some stuff
  }

  _exit(0);
}

Pokud spustíme tento program, uvidíme :

$ ./environ
$

Vidíme tedy, že tentokrát nebyla zavolána čistící funkce ‚exitfunc()‘, což ukazuje rozdíl mezi funkcemi exit() a _exit().


Linux
  1. Najděte nejběžnější procesy podle nejvyššího využití paměti a CPU v Linuxu

  2. Jak definovat a používat funkce v Linux Shell Script

  3. Co jsou linuxové procesy, vlákna, lehké procesy a stav procesu

  1. Linuxové procesy – ID procesů, funkce fork, execv, wait, waitpid C

  2. UNIX / Linux Procesy:C fork() Funkce

  3. Uložte paměť linuxového procesu do souboru

  1. Linux:Najděte a zabijte zombie procesy

  2. Načíst využití CPU a paměti jedním procesem v Linuxu?

  3. Ubuntu Linux:Proces swap paměti a využití paměti