fork练习、从进程角度考虑堆区内存申请与释放的有关问题
1.fork練習
1.1代碼1;
int main( int argc, char* argv[], char* envp[]) {int i = 0;for( ; i < 2; i++ ){fork();printf("A\n");}exit(0); }輸出幾個A?在這里只需要簡單分析就出結果。
如圖:0為最初程序,0-1為0的子進程,0-1-1為0-1的子進程…
簡單分析可知總共產生了4個進程。0進程肯定輸出2A;0-1進程由于0產生此子進程時i = 0,且打印A在創建子進程之后,所以0-1打印2A;0-2為0產生的第二個子進程,由于i=1時創建,所以0-2只打印1A;0-1-1由0-1創建的子進程,同理,打印1A,所以總共打印6個A。
1.2那如果換個代碼呢?如下代碼2:
int main( int argc, char* argv[], char* envp[]) {int i = 0;for( ; i < 2; i++ ){fork();printf("A");}exit(0); }注意和代碼1的區別僅僅少了\n,在printf函數輸出我們已經說過這個問題。這里考慮進程復制之外,還需要考慮緩沖區刷新問題。在這里不進行分析了,只需要在分析代碼一的基礎上,加上對緩沖區的考慮即可,答案也肯定比代碼一的6個A要多。
1.3printf+fork+write問題
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h>int main() {printf("A");write(1,"B",1);fork();exit(0); }分析:見到printf我們就想到printf緩沖區的問題,A放到緩沖區沒有打印,而write是系統調用,直接將B打印到stdout(屏幕上),這時候進行fork()會將緩沖區中的A也進行復制,程序結束后會打印出來AA。所以運行結果是BAA。
1.4代碼四:
#include<stdio.h> #include<unistd.h> #include<stdlib.h>int main() {if(fork()||fork()){printf("A\n")}exit(0); }問:輸出幾個A?
0進程執行第一個fork(),創建了子進程0-1,由于0進程的fork()返回的是子進程的pid所以大于0,為真,后面一個fork()不需要執行;0-1進程的第一個fork()為0,所以需要執行后面一個fork(),創建了子進程0-1-1。所以產生了三個進程,輸出3個A。
2. 從進程的視角看堆區內存申請與釋放的有關問題
(1)在物理內存只有 2G 的系統中,malloc 能否申請 2G 空間,怎么思考?
在計算機基礎中我們談了虛擬內存,很顯然,正常情況下,系統的虛擬內存不會少于2G,物理內存一部分被內核使用,剩下的加上虛擬內存,正常情況下,是可以申請的了2G內存的。
(2)malloc 與 fork,父進程堆區申請的空間復制后,子進程也會有一份,也需要釋放嗎?
事實證明malloc的空間,父子進程都會有一份,且不是共享的。首先看mall.c代碼如下:
編譯運行并沒有出錯,如果是共享空間的話,那么父子進程會對一個空間各free一次,我們都知道,對同一個空間free兩次,編譯運行會出現錯誤。所以父子進程堆空間不共享(這里指的是每個進程的堆空間)。哪怕父子進程對申請的堆空間都沒有操作。
再來看一段代碼:
運行結果為:
父子進程對堆空間里的值進行修改,父進程修改并未導致子進程堆空間的值被修改。所以此時,也不是共享堆的。
這里仍然可以用寫時拷貝理解。malloc申請的空間是對每個進程的地址空間而言的,只有當用到申請的空間,才會映射到底層真時物理空間。
總結
以上是生活随笔為你收集整理的fork练习、从进程角度考虑堆区内存申请与释放的有关问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fork复制进程
- 下一篇: fork与操作文件的系统调用问题