日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Unix/Linux环境C编程入门教程(27) 内存那些事儿

發布時間:2023/11/30 linux 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unix/Linux环境C编程入门教程(27) 内存那些事儿 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • calloc() free() getpagesize() malloc() mmap() munmap()函數介紹
  • calloc(配置內存空間)

    相關函數

    malloc,free,realloc,brk

    表頭文件

    #include <stdlib.h>

    定義函數

    void *calloc(size_t nmemb,size_t size);

    函數說明

    calloc()用來配置nmemb個相鄰的內存單位,每一單位的大小為size,并返回指向第一個元素的指針。這和使用下列的方式效果相同:malloc(nmemb*size);不過,在利用calloc()配置內存時會將內存內容初始化為0。

    返回值

    若配置成功則返回一指針,失敗則返回NULL。

    范例

    /* 動態配置10個struct test 空間*/
    #include<stdlib.h>
    struct test
    {
    int a[10];
    char b[20];
    }
    main()
    {
    struct test *ptr=calloc(sizeof(struct test),10);
    }

      ?




    free(釋放原先配置的內存)

    相關函數

    malloc,calloc,realloc,brk

    表頭文件

    #include<stdlib.h>

    定義函數

    void free(void *ptr);

    函數說明

    參數ptr為指向先前由malloc()、calloc()或realloc()所返回的內存指針。調用free()后ptr所指的內存空間便會被收回。假若參數ptr所指的內存空間已被收回或是未知的內存地址,則調用free()可能會有無法預期的情況發生。若參數ptr為NULL,則free()不會有任何作用。

      ?




    getpagesize(取得內存分頁大小)

    相關函數

    sbrk

    表頭文件

    #include<unistd.h>

    定義函數

    size_t getpagesize(void);

    函數說明

    返回一分頁的大小,單位為字節(byte)。此為系統的分頁大小,不一定會和硬件分頁大小相同。

    返回值

    內存分頁大小。附加說明在Intel x86 上其返回值應為4096bytes。

    范例

    #include <unistd.h>
    main()
    {
    printf("page size = %d\n",getpagesize( ) );
    }

      ?




    malloc(配置內存空間)

    相關函數

    calloc,free,realloc,brk

    表頭文件

    #include<stdlib.h>

    定義函數

    void * malloc(size_t size);

    函數說明

    malloc()用來配置內存空間,其大小由指定的size決定。

    返回值

    若配置成功則返回一指針,失敗則返回NULL。

    范例

    void p = malloc(1024); /*配置1k的內存*/

      ?




    相關函數

    munmap,open

    表頭文件

    #include <unistd.h>
    #include <sys/mman.h>

    定義函數

    void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

    函數說明

    mmap()用來將某個文件內容映射到內存中,對該內存區域的存取即是直接對該文件內容的讀寫。參數start指向欲對應的內存起始地址,通常設為NULL,代表讓系統自動選定地址,對應成功后該地址會返回。參數length代表將文件中多大的部分對應到內存。

    參數

    prot代表映射區域的保護方式有下列組合
    PROT_EXEC 映射區域可被執行
    PROT_READ 映射區域可被讀取
    PROT_WRITE 映射區域可被寫入
    PROT_NONE 映射區域不能存取

    參數

    flags會影響映射區域的各種特性
    MAP_FIXED 如果參數start所指的地址無法成功建立映射時,則放棄映射,不對地址做修正。通常不鼓勵用此旗標。
    MAP_SHARED對映射區域的寫入數據會復制回文件內,而且允許其他映射該文件的進程共享。
    MAP_PRIVATE 對映射區域的寫入操作會產生一個映射文件的復制,即私人的"寫入時復制"(copy on write)對此區域作的任何修改都不會寫回原來的文件內容。
    MAP_ANONYMOUS建立匿名映射。此時會忽略參數fd,不涉及文件,而且映射區域無法和其他進程共享。
    MAP_DENYWRITE只允許對映射區域的寫入操作,其他對文件直接寫入的操作將會被拒絕。
    MAP_LOCKED 將映射區域鎖定住,這表示該區域不會被置換(swap)。
    在調用mmap()時必須要指定MAP_SHARED 或MAP_PRIVATE。參數fd為open()返回的文件描述詞,代表欲映射到內存的文件。參數offset為文件映射的偏移量,通常設置為0,代表從文件最前方開始對應,offset必須是分頁大小的整數倍。

    返回值

    若映射成功則返回映射區的內存起始地址,否則返回MAP_FAILED(-1),錯誤原因存于errno 中。

    錯誤代碼

    EBADF 參數fd 不是有效的文件描述詞
    EACCES 存取權限有誤。如果是MAP_PRIVATE 情況下文件必須可讀,使用MAP_SHARED則要有PROT_WRITE以及該文件要能寫入。
    EINVAL 參數start、length 或offset有一個不合法。
    EAGAIN 文件被鎖住,或是有太多內存被鎖住。
    ENOMEM 內存不足。





      ?




    munmap(解除內存映射)

    相關函數

    mmap

    表頭文件

    #include<unistd.h>
    #include<sys/mman.h>

    定義函數

    int munmap(void *start,size_t length);

    函數說明

    munmap()用來取消參數start所指的映射內存起始地址,參數length則是欲取消的內存大小。當進程結束或利用exec相關函數來執行其他程序時,映射內存會自動解除,但關閉對應的文件描述詞時不會解除映射。

    返回值

    如果解除映射成功則返回0,否則返回-1,錯誤原因存于errno中錯誤代碼EINVAL

    參數

    start或length 不合法。

    范例

    參考mmap()

  • Linux文件與文件描述符的概念
    • 文件的概念

      大多數資源,Linux都是以文件的方式來訪問。

    Linux中主要的文件類型分為4種:普通文件、目錄文件、鏈接文件和設備文件

    Linux中的文件屬性:

    -rwx rwx rwx

    首先,Linux中文件的擁有者可以把文件的訪問屬性設成3種不同的訪問權限:可讀(r)、可寫(w)和可執行(x)。

    文件又有3種不同的用戶級別:文件擁有者(u)、所屬的用戶組(g)和系統里的其他用戶(o)

    第一個字符顯示文件的類型:

    "-"表示普通文件

    "d"表示目錄文件

    "l"表示鏈接文件

    "c"表示字符設備

    "b"表示塊設備

    "p"表示命名管道比如FIFO文件

    "f"表示堆棧文件比如LILO文件

    第一個字符之后的3個三位字符組:

    第一個三位字符組表示文件擁有者(u)對該文件的權限

    第二個三位字符組表示文件用戶組(g)對該文件的權限

    第三個三位字符組表示系統其他用戶(o)對該文件的權限

    若該用戶組對此沒有權限,一般顯示"-"字符

    如圖所示:

    • 文件描述符。

    文件描述符是個很小的正整數,它是一個索引值,指向內核為每個進程所維護的該進程打開文件的記錄表。

  • 內存映射機制與系統調用

    實際上,內存映射機制并不是完全為了共享內存的目的而設計的,它本身提供了不同于一般普通文件的訪問方式,進程可以像訪問內存一樣對普通文件進程操作.而POSIX或System V共享內存IPC則純粹是用于共享內存的目的.當然內存映射實現共享內存,也是內存映射的應用之一

    內存映射機制的用途: A、以訪問內存的方式讀寫文件; B、實現共享內存;

    ?

    mmap()系統調用:
    ?? mmap()系統調用使得進程之間通過映射同一個普通文件而實現共享內存的目的.普通文件被映射到進程的地址空間之后,進程就可以像訪問普通內存一樣對文件進行訪問,不必再調用read()、write()等系統調用操作.

    ?? mmap()系統調用介紹:
    ?? void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);

    ?? 該函數在進程的地址空間與文件對象或共享內存對象之間建立一種映射關系;

    ?? addr? :該參數指定文件應該被映射到進程地址空間的起始地址,一般被指定為一個空指針,此時,程序把選擇起始地址的任務留給內核來完成了.這個地址是進程地址空間中需要映射到文件中的內存區域的首地址;也就是說,在進程地址空間中用于文件映射的內存區域的首地址;

    ?? len?? :文件被映射到調用進程的地址空間中的字節數,它從被映射文件開頭offset個字節處開始算起,取len個字節,把文件中的這len個字節的文件空間映射到進程的地址空間中;

    ?? port? :指定文件被映射到內存中之后的訪問權限.可取的值有:PORT_READ(可讀)、PORT_WRITE(可寫)、PORT_EXEC(可執行)、PORT_NONE(不可訪問);
    ?? flags :映射標記;取值如下:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED和MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用;

    ?? fd??? :即將被映射到進程地址空間中的文件的描述符.一般由系統調用open()返回;同時,fd可以指定為-1,此時,必須指定flags參數中的MAP_ANON,表明進程的是匿名映射(不涉及具體的文件名,避免了文件的創建及打開,很顯然,只能用于具有親屬關系的進程之間的通信).

    ?? offset:從文件開頭計算offset個字節處開始映射;也就是,文件中需要被映射的文件內容的起始地址,這個起始地址的計算是以文件開頭為參照的;這個參數一般取值為0,表示從文件開頭處開始映射;
    ?? 返回值:文件最終映射到進程地址空間中的起始地址;進程可直接以該地址為有效的起始地址進行操作;也就是文件中開始映射的起始字節點到進程中對應映射內存區的起始地址點處的一個映射;換句話就是說,在進程地址空間中用于文件映射的內存區域的首地址;

    系統調用mmap()用于共享內存的兩種方式:
    ?? A、使用普通文件提供的內存映射/共享內存:適用于任何進程之間;此時,需要使用系統調用open()事先打開或創建一個文件,然后再調用mmap():
    ????? fd = open(filename, flag, mode);
    ????? ......
    ????? ptr = mmap(NULL, len, PORT_READ|PORT_WRITE, MAP_SHARED, fd, 0);
    ?????五、解除內存映射關系:
    ?? 當進程間通信結束時,需要解除文件頁面空間到進程地址空間之間的映射關系;也就說,進程通信結束時,需要把掛載到進程地址空間上的文件卸載下來;這個任務由系統調用munmap();
    ?? int munmap(void* addr, size_t len);
    ?? 該系統調用用于在進程地址空間中結束映射關系;
    ?? addr:是調用mmap()返回的進程地址空間中用于文件映射的內存區域的首地址;
    ?? len :進程地址空間中映射區域的大小,單位:字節;
    ?? 當映射關系解除之后,對原來映射地址的訪問將導致段錯誤發生;
    ?? 返回值: -1:失敗; 0:成功;
    內存映射的同步:
    ?? 一般來說,進程在映射空間中對共享內容的修改并不會直接寫回到磁盤文件中,可以通過調用msync()來實現磁盤上文件內容與共享內存區中的內容與一致

  • 小試牛刀

    整體流程就是:

  • 首先打開一個文件,讀取出文件信息
  • 根據文件長度分配相應長度的堆內存
  • Mmap函數做內存映射
  • 從內存映射中開始拷貝內容
  • 輸出函數返回的地址開始的內容
  • 輸出完畢之后關閉內存映射文件
  • 輸出拷貝的文件
  • 釋放內存
  • 關閉文件描述符
  • 源代碼:

    #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h>#include <string.h> int main() { int fd;//文件描述符 char *start = NULL,*flag = NULL;//指針接收文件影射的開始地址 struct stat st; printf("page size = %d\n",getpagesize( ) ); fd=open("read.log",O_RDONLY); /*打開/etc/passwd*/ if(fd < -1) //打開失敗 return -1; printf("打開成功\n"); fstat(fd,&st); /*取得文件大小*/ start =(char *) malloc(st.st_size+1); if(start == NULL) return -1; printf("內存分配成功\n"); flag=mmap(start,st.st_size,PROT_READ,MAP_PRIVATE,fd,0); /*私有不共享*/ if(flag == MAP_FAILED && start != flag) /*判斷是否映射成功*/ return -1; printf("映射成功\n");printf("%s",flag); memcpy(start,flag,st.st_size); printf("輸出完成\n"); munmap(start,st.st_size); /*解除映射*/ printf("解除映射完畢\n");return 0; }

  • 各個平臺的運行情況

    首先創建testmem.c

    再創建read.log

    在RHEL7上的運行情況

    在RHEL6上

    在MAC上

    ?

    在Solaris上

    先進入桌面

    將兩個文件都拷貝過來

  • 轉載于:https://www.cnblogs.com/niulanshan/p/6174851.html

    總結

    以上是生活随笔為你收集整理的Unix/Linux环境C编程入门教程(27) 内存那些事儿的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。