亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Unix > 正文

UNIX高級環境編程(8)進程環境(Process Environment)- 進程的啟動和退出、內存布局、環境變量列表

2024-06-28 13:21:41
字體:
來源:轉載
供稿:網友
UNIX高級環境編程(8)進程環境(PRocess Environment)- 進程的啟動和退出、內存布局、環境變量列表

在學習進程控制相關知識之前,我們需要了解一個單進程的運行環境。

本章我們將了解一下的內容:

  • 程序運行時,main函數是如何被調用的;
  • 命令行參數是如何被傳入到程序中的;
  • 一個典型的內存布局是怎樣的;
  • 如何分配內存;
  • 程序如何使用環境變量;
  • 程序終止的各種方式;
  • 跳轉(longjmp和setjmp)函數的工作方式,以及如何和棧交互;
  • 進程的資源限制

?

1 main函數

main函數聲明:

int main (int argc, char *argv[]);

參數說明:

  • argc:命令行參數個數
  • argv:指向參數列表數組的指針

main函數啟動前:

  • C程序由內核執行,通過系統調用exec;
  • main函數調用前,執行指定的啟動路徑(start-up routine);
  • 可執行文件認為此地址為程序的啟動地址,該地址由鏈接器指定;
  • 啟動路徑從內核獲取參數列表和環境變量,使得main函數可以在稍后被調用時可以獲取這些變量。

?

2 進程終止

一共有8中終止進程的方式,5種正常終止和3種異常終止。

5種正常終止:

  1. 從main函數返回;
  2. 調用exit;
  3. 調用_exit或_Exit;
  4. 最后一個線程返回;
  5. 最后一個線程調用pthread_exit。

3種異常終止:

  1. 調用abort;
  2. 接收到一個信號;
  3. 最后一個線程應答或者一個接收到一個退出請求

啟動地址(start-up routine)同樣也是main函數的返回地址。

要獲取該地址,可以通過以下的方式:

exit (main(argc, argv));

?

退出函數

函數聲明:

#include <stdlib.h>

void exit(int status);

void _Exit(int status);

#include <unistd.h>

void _exit(int status);

函數細節:

  • _exit和_Exit立刻返回到內核;
  • exit函數返回內核前會進行一些清理環境工作;

返回一個整數和調用exit函數,并傳入該整數的作用是相同的:

exit(0);

return 0;

?

atexit函數

函數聲明

#include <stdlib.h>

int atexit(void (*func)(void));

函數細節

  • 每個進程可以注冊32個函數,這些函數可以在主函數調用exit時自動被調用
  • 通過atexit注冊的退出時處理函數稱為退出句柄(exit handlers)
  • 這些退出句柄的調用順序為注冊時的相反順序
  • exit函數第一次調用退出句柄時,會關閉所有打開的流
  • 如果主程序調用了exec系列函數,則所有注冊的退出句柄都會被清空

?

程序啟動和終止流程圖

?NewImage

Example:

#include "apue.h"

?

static void my_exit1(void);

static void my_exit2(void);

?

int

main(void)

{

? ? if (atexit(my_exit2) != 0)

? ? ? ? err_sys("can't register my_exit2");

?

? ? if (atexit(my_exit1) != 0)

? ? ? ? err_sys("can't register my_exit1");

? ? if (atexit(my_exit1) != 0)

? ? ? ? err_sys("can't register my_exit1");

?

? ? printf("main is done/n");

? ? return(0);

}

?

static void

my_exit1(void)

{

? ? printf("first exit handler/n");

}

?

static void

my_exit2(void)

{

? ? printf("second exit handler/n");

}

?執行結果:

NewImage

?

3 命令行參數Example:

#include "apue.h"

?

int

main(int argc, char *argv[])

{

? ? int ? ? i;

?

? ? for (i = 0; i < argc; i++)? ? ? /* echo all command-line args */

? ? ? ? printf("argv[%d]: %s/n", i, argv[i]);

? ? exit(0);

}

執行結果:

NewImage?

?

4 環境變量列表

每個程序會接受一個環境變量列表,該列表是一個數組,由一個數組指針指向,該數組指針類型為:

extern char **environ;

例如,如果環境變量里有5個字符串(C風格字符串),如下圖所示:

NewImage

5 C程序的內存布局

典型的C程序的內存布局如下圖所示:

NewImage

上圖說明:

  • 文本段(Text Segment),保存CPU將要執行的機器指令。文本段是可共享的,所以某個程序多次執行時,對應的文本段只需要在內存中存有一份拷貝。文本段是只讀的(read-only),防止程序的指令被修改。
  • 已初始化數據段(initialized data segment),保存程序中被初始化的全局變量(定義在任何函數之外)。例如:int maxcount = 99; 全局變量變量maxcount被保存在初始化數據段。
  • 未初始化數據段(uninitialized data segment),也被稱為BSS(block started by symbol),這個段中的數據在程序執行之前被內核初始化為0或者null。;例如定義一個全局變量(定義在任何函數之外),long sum[1000]; ?該變量保存在未初始化數據段中。
  • 棧(Stack):存儲臨時變量,函數相關信息。當一個函數被調用時,返回地址、調用者相關信息(如寄存器信息)會被保存在棧中。該被調用的函數會在棧上分配一部分空間保存它的臨時變量。函數的遞歸調用也是應用這個原理。每一次函數調用自己,都會保存當前函數的信息,然后再棧上開辟一個新的空間用于保存該次函數的信息,和以前的函數并沒有影響。
  • 堆(Heap):動態內存分配位置。堆的位置位于未初始化數據段和棧的中間。

?

6 內存分配(Memory Allocation)

有三個函數可以用于內存分配:

  • malloc:分配指定字節數的內存,未初始化。
  • calloc:分配指定數目的對象大小的內存,內存初始化為0;
  • realloc:增加或減小之前分配的內存。移動舊內存的內容到新的更大的內存塊,多余的部分內存未初始化。

函數聲明:

#include <stdlib.h>

void *malloc(size_t size);

void *calloc(size_t nobj, size_t size);

void *realloc(void *ptr, size_t newsize);

void free(void* ptr);

函數細節:

  1. 三個函數返回的內存指針一定是內存對齊的,這樣可以用來保存于不同的對象;
  2. free函數用于釋放ptr指向的內存,被分配的內存放入內存池中用于下次的內存分配;
  3. realloc函數用于改變之前分配的內存的大小。比如運行時我們申請了一段內存用于存儲512個元素的數組,后來發現內存大小不夠,這時可以調用realloc。如果操作系統發現在當前內存的后面有足夠的內存,則直接分配多余的內存到當前內存中,然后返回傳入的指針(即直接擴展內存)。但是如果當前內存后面沒有足夠大小的空間,則系統重新分配一個足夠大的內存,將舊內存塊中得內容拷貝到新內存塊中,然后返回新內存的地址。
  4. 內存分配函數使用系統調用sbrk來實現。該系統調用的作用是擴展進程的堆。
  5. 一般實際分配的內存塊都比請求的要大,多出來的部分用來存儲內存塊大小、指向下一內存塊的指針等信息。寫覆蓋信息記錄區的錯誤是非常隱蔽而且嚴重的。

?

7 環境變量(Environment Variable)

環境變量的字符串形式:

name=value

?內核不關注環境變量,各種應用才會使用環境變量。

獲取環境變量值使用函數getenv。

#include <stdlib.h>

char* getenv(const char* name);

// Returns: pointer to value associated with name, NULL if not found

修改環境變量的函數:

#include <stdlib.h>

int putenv(char* str);

int setenv(const char* name, const char* value, int rewrite);

int unsetenv(const char* name);

?函數細節:

  • 函數putenv傳入一個字符串,形式為name=value,加入到環境變量列表中。如果name已經存在,先刪除舊的定義。
  • 函數setenv傳入一個name和一個value,如果name已經存在,則參數rewrite決定是否覆蓋舊的定義,如果rewrite為非零,則會覆蓋舊的定義。
  • 函數unsetenv刪除name的定義,如果name不存在,也不報錯。?

?修改環境變量列表的過程是一件很有趣的事情

從上面的C程序內存布局圖中可以看到,環境變量列表(保存指向環境變量字符串的一組指針)保存在棧的上方內存中。

在該內存中,刪除一個字符串很簡單。我們只需要找到該指針,刪除該指針和該指針指向的字符串。

但是增加或修改一個環境變量困難得多。因為環境變量列表所在的內存往往在進程的內存空間頂部,下面是棧。所以該內存空間無法被向上或者向下擴展。

所以修改環境變量列表的過程如下所述:

  • 如果我們修改一個已經存在的name:
    • 如果新的value的大小比已經存在的value小或者相當,直接覆蓋舊的value;
    • 如果新的value的大小比已經存在的value大,則我們必須為新的value malloc一個新的內存空間,拷貝新value到該內存中,替換指向舊value的指針為指向新value的指針。
  • 如果我們新增一個環境變量:
    • 首先我們需要調用malloc為字符串name=value分配空間,拷貝該字符串到目標內存中;
    • 如果這是我們第一次添加環境變量,我們需要調用malloc分配一個新的空間,拷貝老的環境量列表到新的內存中,并在列表后新增目標環境變量。然后我們設置environ指向新的環境變量列表。
    • 如果這不是我們第一次新增環境變量,則我們只需要realloc多分配一個環境變量的空間,新增的環境變量保存在列表尾部,列表最后仍然是一個null指針。

?

小結

本篇介紹了進程的啟動和退出、內存布局、環境變量列表和環境變量的修改。

下一篇將接著學習四個函數setjmp、longjmp、getrlimit和setrlimit。

?

?

參考資料:

《Advanced Programming in the UNIX Envinronment 3rd》


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美一区二区三区精品电影| 另类天堂视频在线观看| 日韩av在线免费观看| 欧美激情乱人伦一区| 久久精彩免费视频| 97色在线观看免费视频| 中文字幕v亚洲ⅴv天堂| 精品伊人久久97| 亚洲人午夜精品| 乱亲女秽乱长久久久| 美日韩精品视频免费看| 久久伊人精品一区二区三区| 亚洲网站在线看| 精品国产91久久久| 亚洲欧洲在线看| 国产精品影片在线观看| 日本在线精品视频| 亚洲一区二区福利| 国产99久久精品一区二区永久免费| 永久免费毛片在线播放不卡| 91久久精品国产91久久性色| 久久久免费高清电视剧观看| 日韩在线视频观看正片免费网站| 久久综合久中文字幕青草| 国产精品久久久久久中文字| 色综合久久中文字幕综合网小说| 日本久久久久久久久久久| 欧美激情videoshd| 亚洲一区二区三区xxx视频| 亚洲精品资源美女情侣酒店| 日韩欧美有码在线| 国产美女高潮久久白浆| 欧美日韩国产成人| 另类美女黄大片| 亚洲电影免费观看高清完整版在线观看| 亚洲天堂男人的天堂| 2021久久精品国产99国产精品| 亚洲欧洲xxxx| 一区二区欧美在线| 98精品国产高清在线xxxx天堂| 欧美综合一区第一页| 亚洲国产精品久久精品怡红院| 欧美福利视频在线| 日韩hd视频在线观看| 久久久精品影院| 国产精品久久久久久搜索| 中文字幕日韩综合av| 久久久久国产精品免费| 91久久精品国产91久久性色| 欧美不卡视频一区发布| 韩剧1988在线观看免费完整版| 久久99青青精品免费观看| 亚洲的天堂在线中文字幕| 久久久久日韩精品久久久男男| 91国内揄拍国内精品对白| 久久久久免费视频| 欧美丝袜美女中出在线| 2019日本中文字幕| 最近2019中文免费高清视频观看www99| 欧美成人在线影院| 亚洲国产精品久久91精品| 欧美黄色三级网站| 日韩有码在线视频| 国产成人精品网站| 在线观看欧美www| 国产玖玖精品视频| 国产精品成人一区二区| 亚洲国产精久久久久久久| 欧美专区在线视频| 国产91精品黑色丝袜高跟鞋| 亚洲一区www| 96精品视频在线| 日韩va亚洲va欧洲va国产| 成人精品一区二区三区| 91香蕉国产在线观看| 国产精品丝袜久久久久久不卡| 国产精品视频午夜| 国产精品久在线观看| 亚洲成人动漫在线播放| 最好看的2019的中文字幕视频| 日韩在线视频观看正片免费网站| 国内精品模特av私拍在线观看| 日本成熟性欧美| 国产视频精品xxxx| 亚洲精品丝袜日韩| 亚洲午夜精品视频| 欧美巨乳在线观看| 韩曰欧美视频免费观看| 国产91露脸中文字幕在线| 国产一区二区三区中文| 亚洲精品在线不卡| 97国产精品人人爽人人做| 久久精品久久精品亚洲人| 成人黄色在线播放| 久国内精品在线| 日韩av中文字幕在线免费观看| 日韩中文字幕在线视频播放| 欧美成人一区在线| 国产福利精品av综合导导航| 热久久这里只有精品| 欧美丰满老妇厨房牲生活| 欧美做爰性生交视频| 精品视频9999| 日韩亚洲一区二区| 高清日韩电视剧大全免费播放在线观看| 欧美日韩福利电影| 亚洲一区二区三区777| 国产欧亚日韩视频| 午夜精品三级视频福利| 成人免费看黄网站| 992tv在线成人免费观看| 在线不卡国产精品| 日韩精品中文字幕久久臀| www高清在线视频日韩欧美| 久久精品在线播放| 美女撒尿一区二区三区| 国产精品中文在线| 亚洲视频777| 国产精品69精品一区二区三区| 在线精品91av| 亚洲一区二区在线播放| 国产亚洲人成a一在线v站| 日韩欧美第一页| 亚洲老头同性xxxxx| 国产97色在线|日韩| 日韩欧美在线观看| 国产乱肥老妇国产一区二| 正在播放国产一区| 亲爱的老师9免费观看全集电视剧| 亚洲高清不卡av| 欧美激情xxxx| 国产精品日韩av| 久久久综合免费视频| 欧美福利视频在线观看| 国产有码在线一区二区视频| 国内伊人久久久久久网站视频| 日韩欧美在线视频日韩欧美在线视频| 精品久久久久久中文字幕大豆网| 欧美午夜电影在线| 亚洲美女久久久| 久久国内精品一国内精品| 97精品视频在线| 欧美中文在线观看国产| 成人免费大片黄在线播放| 欧美日韩高清在线观看| 国产成人精品网站| 国产香蕉一区二区三区在线视频| 日韩欧美精品中文字幕| 九九久久国产精品| 91精品免费久久久久久久久| 久久久国产在线视频| 狠狠躁18三区二区一区| 日韩av免费在线看| 中文.日本.精品| 不卡在线观看电视剧完整版| 亚洲精品国产综合区久久久久久久| 国产精品久久久久一区二区| 国产裸体写真av一区二区| 久久久久久有精品国产| 色999日韩欧美国产| 成人激情视频在线观看| 久精品免费视频| 国产精品偷伦视频免费观看国产| 中文字幕久热精品视频在线|