美文网首页
linux-03-内存管理

linux-03-内存管理

作者: vera姐姐 | 来源:发表于2016-05-07 22:01 被阅读66次

    昨天的复习:环境标 就是内存中环境变量的首地址,是一个 字符指针数组,以NULL元素作为结束,环境表的引入方式:extern char ** environ;

    main()函数的第三个参数也是环境表的首地址

    今天:关于环境变量的标C库函数Unix/LInux的内存管理(机制和实现函数)环境变量库函数:(只针对本进程)getenv()/setenv()/putenv()unsetenv()/clearenv()

    getenv() -按环境变量的名 取得 环境变量的值

    setenv() 新增环境变量或修改/不改变 已经存在的环境变量

    putenv()  新增环境变量或是修改已存在环境变量

    unsetenv() 删除一个环境变量

    clearenv() 删除全部的环境变量

    Unix/Linux的内存管理(UC的真正的开始)

    内存分配和回收的相关函数及实现关系进程的内存空间划分

    虚拟内存地址空间机制内存管理的相关函数:

    自动管理内存  STL容器(各种数据结构)/JAVA

      |

      new分配      C++的内存管理delete回收 

    |

    malloc()分配free()回收  C程序员的内存管理 

    |

    sbrk() brk()    Unix系统函数 UC程序员 (既能分配也能回收) 

    |

    mmap()分配munmap()回收  Unix系统函数 UC程序员 

    |              (用户层)

    ------------------------------------

    kmalloc() vmalloc()  (内核层)

    进程的内存空间划分进程是什么?-运行在内存中的程序

    程序是什么?-就是硬盘上的可执行文件,是编译连接的产物

    为了沟通的方便,很多情况下,把进程也统称为程序

    进程的内存空间划分为以下部分:

    1.代码区 -存放代码(函数)的区域,函数指针就是指向代码区,是函数在代码区的地址。是一个只读区域。

    2.全局区域 -存放全局变量和static修饰的局部变量,能读能写

    3.BSS段-存放未初始化的全局变量。(没有写=的)

    注:全局区和BSS段都会在main()函数执行前创建,区别在于BSS段在main()函数执行之前 会自动清0一次。

    int a;int main(){int b;printf("%d,%d",a,b);//0,和随机数}

    4.栈区/堆栈区(- stack)-没有用static修饰的局部变量,包括函数的形参。栈区的内存系统 系统自动管理。程序员也可以痛过特定函数进行管理的参与,但是不建议使用。

    5.堆区(heap)-也叫自由区,是程序员全权管理的区域。系统不会自动对堆区做任何的事情。malloc()等函数都是在操作堆区。堆区内存的分配和回收都是由程序员完成。

    6.只读常量区 - 很多书上把这个区域并入了代码区,字符串的字面值(“”括起来的)和const修饰的全局变量

    虚拟内存地址空间

    在Unix系统中,程序员所接触的内存地址都是虚拟内存地址,而不是真实的物理内存地址。虚拟内存地址 其实就是一个整数,本质上是不能存储数据的,需要做内存映射后才能存储数据。每个进程在启动时就先天具备了0-4G的虚拟内存地址空间(32位系统),这些地址都是一个整数,而无法存储数据。虚拟内存地址必须映射到物理内存/硬盘文件 后才能存储数据。所谓的内存分配就是 先分配未使用的虚拟内存地址,再用虚拟内存地址映射到物理内存/硬盘文件。如果使用了未映射的虚拟内存地址 存储数据就会引发 段错误。
    进程之间即使是相同的虚拟内存地址 对应的物理内存也是不一样的。 Unix/Linux系统 用一个整数(虚拟内存地址) 代表一块物理内存。

    虚拟内存地址是按字节管理的(一个字节有一个虚拟地址),但是在做内存映射时不是以字节为单位做映射,而是用内存页做映射的基本单位。一个内存页(32位系统)是4096(4k),函数getpagesize()可以获取内存页的大小。(空间换时间)先分配4k的空间,等用完了4k的空间再分配 malloc(4)-》分配了4字节的虚拟地址,但是映射了33页物理内存

    0-4G的虚拟内存地址 分为用户空间和内核空间,用户空间是0-3G,3G-4G是内核空间,用户空间是给用户使用,内核空间是给系统内核使用,用户空间的程序不能直接访问内核空间,但可以通过Unix提供的系统函数(系统调用)进入内核空间。

    关于数组和指针:大多数情况下,数组和指针可以混合使用,但是有区别:

    1.sizeof()不一样,数组的sizeof()是数组的长度乘以元素的大小,而指针的sizeof()是4(32位系统)。

    2.指针可以改变地址的指向,而数组是常指针(指向地址不能改变);

    3.函数的返回值不能是数组,因此如果返回数组时,返回值类型必须写指针。void fa(){char *s1 = "abc";//只读常量区 因为指针的指向可以该,所以直接指向了“abc“所在的只读常量区

    char s2[4] = "abc";//在堆区,因为数组是常量指针,一开始就指向了堆区,由于常量指针的指向是不可以更改的,故直接把”abc“复制到了堆区}

    进程内存空间的排序次序(由小到大)

    代码区 只读常量区 全局区 BSS段 堆区 栈区

    堆区的分配方式是从小到大

    栈区的分配方式是从大到小其中,栈区在3G左右的位置。

    Linux系统 中,文件可以代表 几乎一切,内存有文件与之对应,输入输出设备 也有文件与之对应,目录 也是 文件。

    cat /proc/pid/maps 可以查看内存映射的情况,其中pid就是进程编号ID,可以用getpid()函数取得(进程不结束就有效)

    字符串处理和数据结构是每个程序员的基本功,作为c程序员操作字符串的基本代码。(超重要)

    出 段错误的可能:1.使用了未映射的虚拟内存地址2.对内存进行了没有权限的操作,比如:修改了只读区

    //字符串的基本代码

    5 //c语言中,字符串只能用char *或char s[]

    6 int main()

    7 {

    8 //1.字符串赋值 等号赋值,该的是地址,strcpy()该值,不改变指向

    9    char* s1 = "abc";

    10    char s2[4] = "abc";//初始化是例外,改值

    11    s1 = "123";//y

    12    strcpy(s1,"123");//n 段错误 只读区域是不能改值的

    13    s2 = "123";//n 数组是常指针,常指针不能该地址

    14    strcpy(s2,"123");//y  数组可以改元素值

    15

    16    char* s3 = malloc(4);

    17    s3 = "123";//n 不行的原因是因为等号改变了堆区的指向,指向了只读常量区,>    虽然不会报错,但是会导致释放不了  指向只读区,堆区内存泄漏 堆区和栈区分配了>    地址,所以一般都用strcpy

    18    strcpy(s3,"123");//y 直接改变值,不改变指向,所以堆区还有权限释放自己

    19    printf("s4 = %s\n",s3);

    20    free(s3);

    21 }

    相关文章

      网友评论

          本文标题:linux-03-内存管理

          本文链接:https://www.haomeiwen.com/subject/mvnrrttx.html