[轉]C程序運行、退出過程及內存分配

1、內核執行C程序(用exec)
   在調用main函數之前會調用一個特殊的啓動程序
   它從內核中獲取 命令行參數和環境變量 供main函數使用
   可執行程序以它作爲程序的開始地址
2、C程序的開始和結束
Fig.1 How a C program is started and how it terminate
注1:#include <stdlib.c>
    void exit(int statues);
    void _Exit(int statues);
    #include <unistd.h>
    void _exit(int status);
    後2個函數立即返回內核
    第1個函數首先執行exit handlers,執行flush buffer(all buffered datas be flushed),關掉標準IO庫,用fclose關掉所有打開的streams
注2:exit(0) 等同於 return(0)
注3: #include <stdlib.h>
     int atexit(void (*func)(void));
     (用於註冊exit handlers)
注4:除了exit系列函數,還有信號可以終止進程

3、命令行參數 和 環境變量
   for(i = 0; i <argc; i++)
   ISO C和POSIX.1都確保argv[argc]是NULL,所以
   for(i = 0; argv[i] != NULL; i++)

   extern char **environ;(字符串數組)
   i.e: HOME=/home/sar/0
        PATH=:/bin:/usr/bin/0
        SHELL=/bin/bash/0
        USER=sar/0
        LOGNAME=sar/0
   最早的時候寫成
   int main(int argc, char *argv[], char *envp[])
   但POSIX.1規定最後一個變量用getenv系列函數來操作
   #include <stdlib.h>
   int putenv(char *str);
   int setenv(const char *name, const *value, int
              rewrite);
   int unsetenv(const char *name);

4、C程序內存佈局
Fig.2 Typical memory arrangement
注1:.text----CPU執行的機器指令,只讀,共享(任何C程序可用)
     .data----初始化的數據
     .bss----"block started by symbol"(古老的彙編運算符)C declaration
    
注2:LINUX intel x86下,.text起始於0x08048000,stack底低於
     0xC0000000

注3:只有.text 和.data 需要存儲,而.bss在程序開始運行之前全部被設置爲
     0或者NULL

注4:可以用size命令查看各部分大小
     $size /usr/sh

注5:一般以靜態方式進行編譯的可執行文件通常會很大,那是因爲以普通方
    式(共享庫模式)編譯,共享庫從可執行文件移出了通用庫routines,而
    通過在內存中爲所有程序維持一份拷貝作爲參考

5、內存分配
   #include <stlib.h>
   void *malloc(size_t size);
   void *calloc(size_t nobj, size_t size);
   // a specified number of objects of a specified size,i
   // initialzied to all 0 bits
   void *realloc(void *ptr, size_t newsize);
   // increases or decreases the size of a previously allocated area
   void free(void *ptr);
注1: 分配的內存都被確保很好的aligned
注2: 它們一般都是通過sbrk()系統調用來實現
注3: 通常分配的內存比程序的指定要大點,因爲需要一些附加的空間來記錄
      分配塊的打消,下一個分配塊的指針等等。所以寫這一部分是件不允許
      的事情
注4: 忘記free,那麼只要程序在運行,進程內存的使用就會持續增加直到
      無內存可用,這叫leakage

6、setjmp和longjmp(跨越函數的跳躍)
   #include <setjmp.h>
   int setjmp(jmp_buf env);
   void longjmp(jmp_buf env, int val);

注1:jmp_buf----數組形式,保存所有需要的信息存儲到stack直到調用
     longjmp
     val----非0,作爲從setjmp的返回值
     if (setjmp(jmbbuffer) != 0)
     ...
     longjmp(jmpbuffer, 1);
注2:這兩個函數在編譯優化的時候並不影響globlal,static和volatile變量
     但是影響automatic和register變量。因爲在CPU裏的變量和浮點寄存器
     在setjmp調用時就已經存儲好了,其他存儲在內存的變量與longjmp時的
     值一樣

7、getrlimit和setrlimit(獲取和設置系統資源限制)
   #include <sys/resource.h>
   int getrlimit(int resource, struct rlimit *rlptr);
   int setrlimit(int resource, const struct rlimit *rlptr);
   (0 if OK, nonzero on error)
注1:系統資源----比如data段的大小,程序使用的最大空間等等
注2:resource limits影響調用進程和子進程
     resource limits可以設置到shell影響所有進程(ulimit命令)
該人的博客裏,還有不少關於算法的,例如圖,希爾排序等算法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章