虚拟地址空间:传统的进程管理每个进程都占连续的物理内存空间,如果内存爆满需要将很久没用的但还在内存中的整个进程拷贝到硬盘中,等需要用时重新加载回内存。现代计算机使用虚拟地址空间,虚拟地址空间每个进程的4g并不是真的有,像是老板给员工画大饼,如果努力有可能达到,职位可能只有两个,因为整个计算机实际运行内存才8g。为了减少内存移动,提高利用率,隔离进程保护安全,加入了虚拟的地址,把内存分割成很多页(一个页4k)映射存储,需要经过MMU芯片转换才能访问实际物理内存。因为4k很小,所以可以嵌入很多被使用的内存块中间,而不像传统的进程那样即使夹杂在进程A和B有100mb,但我需要150mb,而E和F之间也有60mb,如果分开存储那够了,但不好意思一个进程内存不允许切开,C得暂时避让。
虚拟地址空间包括内核区和用户区,用户区从上到下是栈、映射区、堆、未初始化默认为0的全局区(static静态区)、已初始化的全局区、常量区(字符串以及const常量)、代码区。全局变量区、堆区是每个应用进程独享的内存。内核区是系统管理的代码,每台电脑只有一个实体(物理内存),共享区是动态链接库代码,把常用的功能都集成在里面多个应用可共用。
而代码区是进程共享的,即函数的语句,指使着如何运算,他们之间的逻辑关系,运用哪个数据进行怎样的操作,比如y=x*x+3;全部都是已知指令,但是该数据可以是地址间接引用如变量x,具体的内容是变化的,到栈区去找,也可以是固定的立即数3。函数别称功能、方法,是代码集合,可重复调用,可看成一个榨汁机,而参数就是放进去的水果,函数里面的代码就是榨汁机的功能,就是无论把什么果放进去都是一样的流程,即绞碎。但结果也会由于放进的水果不同而产生的果汁也不一样。也可以把函数里面的内容(栈区中的临时变量)当成草稿纸上的计算,而要写在试卷的答案是函数返回值。为什么要有函数?调用者无需关心底层事情,比如一个蛋糕师,他可能懂得奶油是怎么来的,但是为了方便直接买来(调用函数),然后再和水果、面包等拼装成蛋糕。为什么叫形式参数?因为函数代码只是假设有这个变量时该怎么操作,相当于练功夫时把身前的空气当作人,起占位作用。栈区是每个线程独享,是函数的运行地,
堆区是隐式链表,由block组成,每个block保存着内存块区域大小以及使用状态。malloc的原理,有最佳适配,就是需要开辟的内存和左右已用块之间夹着的空闲块相差值最小,提高空间利用率;首次适配算法:从头开始扫描,一有空闲块大于将要开辟的大小就立即占用,时间较短但可能造成空隙大浪费空间。因为堆区一开始不知道要使用多少内存,需要动态开辟,堆区一开始向系统申请一块大内存(128k到几mb),然后零售给程序中的各函数使用。调用malloc时,只是分配了对应的虚拟地址空间。只有当访问该部分内存时产生缺页反应才会真正分配物理内存并将物理内存和虚拟内存建立映射关系。。free只是归还给虚拟空间,并未真正释放,如果有malloc函数扫描到之前的释放的块那可直接使用,而不用向系统频繁申请空间。等到调用malloc函数时查找块从头到尾遍历完了实在没有空闲块就会移动堆区有效指针break以实现扩容,是内核调用,花费时间。如果用到了新的页面就要分配物理页。如果指针在同一个页面里面移动就不用。
在虚拟地址空间中文件映射段(动态库/共享区)mmap是用来将硬盘中的文件映射到内存中以加快效率,直接在内核缓冲区操作减少复制在用户缓冲区的过程。2.也可以作为dll系统库共享区3.还可以作为堆的功能,如果heap堆区满了再向上推break指针以实现真正的扩容,但是当要申请的空间大于128k,直接使用mmap申请开辟,释放时不是归还给程序管理,而是可以直接单独释放对应的物理内存。堆区高地址部分的块释放后还有堆顶指针brk附近的连续空闲内存大于128K时,将进行真正意义上的内存回收,才把堆指针往下降;如果高地址的块还没free,在它下面的块即使free也不会单独释放。