精华内容
下载资源
问答
  • 操作系统课程的实验,内存管理 内存分配实验,用VC++实现的
  • 掌握为实现多道程序并发...系统如何为进入内存的作业分配内存空间,实现多道作业同时驻留内存,就绪进程队列中的多个进程是如何以分式方式共享CPU,作业运行完成离开系统时,系统如何进行内存回收,计算进程周转时间。
  • 操作系统内存分配算法

    千次阅读 2019-08-22 16:12:47
    缺点: 需要通过遍历的方式才能知道哪些内存是可以使用的,并且这种内存分配方式不能避免内存碎片的问题。 链式算法 概念: 这种分配算法通过链表来保存和维护块的使用信息,它包括多个单元,每个单元是一个连续的...

    位图算法

    概念: 这种位图即二维数组,通过二维数组来保存内存的使用情况,每个位的值代表这个块的使用情况,0为空闲,1为被占用。
    优点: 查找快;对于内存的管理比较清晰可见。
    缺点: 需要通过遍历的方式才能知道哪些内存是可以使用的,并且这种内存分配方式不能避免内存碎片的问题。

    链式算法

    概念: 这种分配算法通过链表来保存和维护块的使用信息,它包括多个单元,每个单元是一个连续的数组,数组的第一位用来表示这个数组是用来表示的是已占用块信息还是空闲块信息,第二位是块的起始点,第三位表示从这个位置出发有多少个块是被占用(空闲)的,数组的最后一位存放的是指向下一个数组的首部地址的指针。
    如何操作: 当某个块可以直接被使用时,就可以修改它的状态并分配内存;如果只需要使用其中的一部分,那么可以把它拆开,分为两个链表元素,当被分配的块被释放后,再合并这两块内存。
    优点: 方便进行内存的分配和回收,对链表修改速度快。
    缺点: 需要遍历链表才能找到合适的内存区间。

    伙伴(buddy)算法

    在这里插入图片描述
    概念: 这种方式基于数组结合链表来实现,它解决了链式算法查找慢的问题,伙伴算法对不同大小的内存进行分类管理,可以根据内存分配的需求直接定位到相应位置,提升内存查找速度。伙伴算法的数据结构是通过一个free_area的数组,找到合适的数量级的位置,这个位置维护着一段链表,如果对应链表元素可用,就进行分配,同时还可以对剩下的内存进行拆分,并把它们调整到低数量级,可用于分配小对象,当这块内存对应区域被释放后,就可以和相邻的内存区间合并,再添加到高一数量级的数组位置。
    返回错误的情况: 假设当需要使用512大小的页框,发现对应位置不存在可用的页框,则去1024的位置去查找,是否有可用的内存,如果可用,则取出其中可用的部分并把剩下的划分到上一级,如果一直没有找到可用内存,则返回错误。
    优点: 可以迅速找到合适大小的内存,且方便对内存的拆分和合并;一定程度上解决了内存碎片的问题,把外部碎片转移到内部。
    缺点: 依然存在内部内存碎片的问题,在分配小对象的时候容易导致内存的浪费,比如需要大小为9的内存块必须分配大小为16的内存块。对于小对象频繁的分配和回收会造成不必要的cpu浪费。另外假设一种情景,如果当前只有大小为1024的内存,当需要申请一段16段内存之后,剩下的内存就会被分割,如果再申请600的内存就得不到了,这也是这种算法的一个弊端。
    优化: 当链表中内存块个数小于某个值的时候,并不合并伙伴内存块,只要当高于低潮个数的时候才合并。

    slab算法

    在这里插入图片描述
    概念: slab在一定程度上优化了伙伴算法的小对象浪费内存的问题,slab分配器在操作系统初始化的时候就维护了一个缓存区域,维护了一个slabs列表,每个slab中存储着若干对象,用来缓存内核中需要频繁创建和销毁的小对象,对它们完成初始化操作,并放置在缓存中,以实现通用对象的复用。
    三种状态:
    1、slabs_full:完全分配的 slab。
    2、slabs_partial:部分分配的 slab。
    3、slabs_empty:空 slab,或者没有对象被分配。
    优点:
    1、内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。
    2、slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。
    3、slab 分配器还支持通用对象的初始化,从而避免了为同一目的而对一个对象重复进行初始化。
    4、slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。

    展开全文
  • 动态和静态分配两种分配方式 分别模拟FF、BF、WF三种适应算法动态地创建进程 能够动态地销毁进程并更新可用表与已分配表 显示出各个时间段内存块中已分配表与可用表的情况
  • 系统如何为进入内存的作业分配内存空间,实现多道作业同时驻留内存,就绪进程队列中的多个进程是如何以分式方式共享CPU,作业运行完成离开系统时,系统如何进行内存回收,计算进程周转时间。 掌握各种调度算法,以及...
  • C语言——操作系统内存分配过程

    千次阅读 2018-03-27 13:49:08
    内存分配机制的发展过程: 第一阶段——程序直接操作物理内存。 某台计算机总的内存大小是128M,现在同时运行两个程序A和B,A需占用内存10M,B需占用内存100。计算机在给程序分配内存时会采取这样的方法:先将...

    内存分配机制的发展过程:

    第一阶段——程序直接操作物理内存。

    某台计算机总的内存大小是128M,现在同时运行两个程序A和B,A需占用内存10M,B需占用内存100。计算机在给程序分配内存时会采取这样的方法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分出100M分配给程序B

    1.进程地址空间不隔离。

    进程之间可以互相修改内存,导致不安全,可能会出现一个进程出现bug,导致另一个本来好好的进程挂掉。

    2.内存使用效率低。

    在A和B都运行的情况下,如果用户又运行了程序C,而程序C需要30M大小的内存才能运行,而此时系统只剩下18M的空间可供使用,所以此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序C使用,然后再将程序C的数据全部装入内存中运行。

    3.程序运行的地址不确定。

    当内存中的剩余空间可以满足程序C的要求后,操作系统会在剩余空间中随机分配一段连续的20M大小的空间给程序C使用,因为是随机分配的,所以程序运行的地址是不确定的。

    虚拟内存
    虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。

    第二阶段——分段(解决了第一阶段的第1和第3个问题)

    在进程和物理内存增加一个中间层,利用一种间接的地址访问方法访问物理内存。程序中访问的内存地址不再是实际的物理内存地址,而是一个虚拟地址,然后由操作系统将这个虚拟地址映射到适当的物理内存地址上。这样,只要操作系统处理好虚拟地址到物理内存地址的映射,就可以保证不同的程序最终访问的内存地址位于不同的区域,彼此没有重叠,就可以达到内存地址空间隔离的效果。

    第三阶段——分页(解决了第一阶段的第2个问题)

    将地址空间分成许多的页。每页的大小由CPU决定,然后由操作系统选择页的大小。目前Inter系列的CPU支持4KB或4MB的页大小,而PC上目前都选择使用4KB。

    对比分段

    在分段的方法中,每次程序运行时总是把程序全部装入内存,而分页的方法则有所不同。分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,然后建立虚拟地址空间中的页和刚分配的物理内存页间的映射。

    举例说明加载可执行文件的过程
    一个可执行文件(PE文件)其实就是一些编译链接好的数据和指令的集合,它也会被分成很多页,在PE文件执行的过程中,它往内存中装载的单位就是页。当一个PE文件被执行时,操作系统会先为该程序创建一个4GB的进程虚拟地址空间。前面介绍过,虚拟地址空间只是一个中间层而已,它的功能是利用一种映射机制将虚拟地址空间映射到物理地址空间,所以,创建4GB虚拟地址空间其实并不是要真的创建空间,只是要创建那种映射机制所需要的数据结构而已,这种数据结构就是页目和页表。

    .当创建完虚拟地址空间所需要的数据结构后,进程开始读取PE文件的第一页。在PE文件的第一页包含了PE文件头和段表等信息,进程根据文件头和段表等信息,将PE文件中所有的段一一映射到虚拟地址空间中相应的页(PE文件中的段的长度都是页长的整数倍)。这时PE文件的真正指令和数据还没有被装入内存中,操作系统只是根据PE文件的头部等信息建立了PE文件和进程虚拟地址空间中页的映射关系而已。当CPU要访问程序中用到的某个虚拟地址时,当CPU发现该地址并没有相相关联的物理地址时,CPU认为该虚拟地址所在的页面是个空页面,CPU会认为这是个页错误(Page Fault),CPU也就知道了操作系统还未给该PE页面分配内存,CPU会将控制权交还给操作系统。操作系统于是为该PE页面在物理空间中分配一个页面,然后再将这个物理页面与虚拟空间中的虚拟页面映射起来,然后将控制权再还给进程,进程从刚才发生页错误的位置重新开始执行。由于此时已为PE文件的那个页面分配了内存,所以就不会发生页错误了。随着程序的执行,页错误会不断地产生,操作系统也会为进程分配相应的物理页面来满足进程执行的需求。

    分页方法的核心思想就是当可执行文件执行到第x页时,就为第x页分配一个内存页y,然后再将这个内存页添加到进程虚拟地址空间的映射表中,这个映射表就相当于一个y=f(x)函数。应用程序通过这个映射表就可以访问到x页关联的y页了。

    内存管理

    最小存储单位是一个字节(1B),最小管理单位是一页(4KB),虚拟内存地址连续时物理内存地址可以不连续,即使一次分配6000字节(不到两页也分配两页),两个内存页物理地址可能不连续。多次申请内存时,如果之前分配的页内存没用完,则不再分配,除非之前分配的内存页用完才继续映射新的一页。硬盘也是如此(硬盘上称为Block块)。

    例如test文件里面只有4个字符,却也需要占4K的大小。
    这里写图片描述

    C语言中的malloc函数

    #include<stdio.h>
    #include<stdlib.h>
    int main(void){
    
        char * p = malloc(0);
    
        printf("%d,%d\n",*(p),*(p+32*4096));//打印第33页的内容,被默认初始化。
    
        free(p);
    }

    运行结果如下:
    这里写图片描述

    #include<stdio.h>
    #include<stdlib.h>
    int main(void){
    
        char * p = malloc(0);
    
        printf("%d,%d\n",*(p),*(p+33*4096));//打印第4页的内存位置,报段错误
    
        free(p);
    }

    运行结果如下:段错误是因为超过的虚拟内存地址并没有映射(分配)物理内存。
    这里写图片描述

    free函数

    malloc()给变量分配给变量内存时,除了数据区域外,还额外需要保存一些信息。底层有一个双向链表保存额外信息。malloc()给指针了12个字节,其中4个字节存放数据,另外8个存放其他信息或者空闲,如果将12个字节中前(低位)几个字节清空或者进行修改,free就可能出错,因为free只有首地址不能释放,还得需要额外附加信息(如malloc分配的长度)

    修改malloc申请的内存的指针位置,free会无法正常释放内存。
    这里写图片描述

    上图中的:
    这里写图片描述

    这里写图片描述

    此处又再次证明了malloc每一次分配的的内存页是33页。

    修改malloc申请的内存的指针的前几位的值,free也会无法正常释放内存。

    这里写图片描述

    参考文章https://blog.csdn.net/ljabclj/article/details/44155221

    展开全文
  • 算法思想:将内存块中的所有的块按照地址递增的顺序连接成一个链表,每次要将新的作业放入内存的时候就按顺序查找内存块链表,每次都是用找到的可以用的第一个内存块。链表数据结构:链表结点共有4个区域和一个下...

    算法思想:

    将内存块中的所有的块按照地址递增的顺序连接成一个链表,每次要将新的作业放入内存的时候就按顺序查找内存块链表,每次都是用找到的可以用的第一个内存块。

    链表数据结构:

    链表结点共有4个区域和一个下指针构成,四个区域分别记录该内存块的起始地址,该内存块长度,内存块的状态和内存块存放的作业编号(没有作业时存放的是0)。

    模拟实现的策略:

    1.插入操作时依照地址递增的顺序检查可以装入的第一个内存块
    若找到,则装入内存中,并且把内部碎片分出来变成新的结点插入链表中
    若没找到则分配失败
    2.撤销操作时按照作业编号找到要撤销作业所在内存块
    若找到,则将状态置位未分配,此时假如前后有可以合并的空内存块则合并

    若没有找到,则返回没有找到该作业信息

    实现代码:

    #include <stdio.h>
    #include <stdlib.h>
    /*
    算法思想:
    1.插入操作时依照地址递增的顺序检查可以装入的第一个内存块
    若找到,则装入内存中,并且把内部碎片分出来变成新的结点插入链表中
    若没找到则分配失败
    2.撤销操作时按照作业编号找到要撤销作业所在内存块
    若找到,则将状态置位未分配,此时假如前后有可以合并的空内存块则合并
    若没有找到,则返回没有找到该作业信息
    */
    
    //使用链表的数据结构
    typedef struct LNode{
    	int address;//表示该分区的起始地址
    	int length; //表示该分区的长度
    	int state;  //0表示该分区空闲,1表示该分区已分配
    	int number; //作业的编号
    	struct LNode *next;
    }*pLNode;
    
    //链表的插入操作
    //L是链表的头指针,addr是该内存块的首地址,len是该内存块的长度
    //sta是内存块的状态,num是将占有内存块作业的编号
    void InsertLNode(pLNode L,int addr,int len,int sta,int num) {
    	pLNode p = (pLNode)malloc(sizeof(LNode));
    	p->address = addr;
    	p->length = len;
    	p->state = sta;
    	p->number = num;
    	p->next = NULL;
    	L->next = p;
    }
    
    //初始化链表
    //初始化链表的头指针,假设操作系统有8M的内存空间,且始址为0
    //leng为内存空间的总大小,单位为M
    void InitLNode(pLNode L,int leng){
    
    	//L = (pLNode)malloc(sizeof(LNode));
    	L->address = 0;//从首地址开始
    	L->length = 8;
    	L->state = 1;
    	L->number = 65535;
    	//插入剩余的空闲分区
    	InsertLNode(L, 8, leng - 8,0,0);
    	printf("初始化成功!\n");
    }
    
    //撤销作业
    //L为链表头指针,num为待撤销的作业编号
    //若找到该作业则把其占有的内存块state置0
    void Revocation(pLNode L, int num) {
    	pLNode p = L->next;
    	if (p->number == num) {
    		//找到了这个作业
    		p->state = 0;
    		printf("成功撤销编号为%d的作业!\n",num);
    		return;
    	}
    	while (p->next != NULL) {
    		p = p->next;
    		p->state = 0;
    		printf("成功撤销编号为%d的作业!\n", num);
    		return;
    	}
    	printf("撤销作业失败,没有找到编号为%d的作业\n", num);
    }
    
    //检查链表中是否有连续的未分配内存区,如果有就合并
    void Merge_free(pLNode L) {
    	pLNode p = L,pre;
    	int num = 0;//用于检测连续空闲内存空间数量,等于2表示有连续的内存空间
    	while (p != NULL) {
    		if (p->state == 0) {
    			//表示为空闲区
    			num++;
    			if (num == 1)
    				pre = p;//为合并做准备
    			else if (num == 2) {
    				//表示有连续的空闲区,执行合并操作
    				//将p结点的长度加给前驱结点的长度
    				//前驱结点指向p结点的下结点
    				//释放p结点
    				//将p指向前驱结点,方便下次判断
    				//num置1
    				pre->length += p->length;
    				pre->next = p->next;
    				free(p);
    				p = pre;
    				num = 1;
    			}
    		}
    		else if (p->state == 1)
    			num = 0;
    		p = p->next;
    	}
    }
    
    //为作业分配内存空间
    //L为链表头指针,len为作业需要的内存大小,num为作业编号
    void Allocation(pLNode L, int len, int num) {
    	pLNode p = L->next;
    	while (p != NULL) {
    		if (p->state == 0) {
    			//表示内存块未分配
    			if (p->length > len) {
    				//表示可以分配内存空间
    				//但是需要把内部碎片分出来,构成新的空闲内存块
    				//新的内存块的起始地址为p->address + len,长度为p->length-len
    				pLNode l = (pLNode)malloc(sizeof(LNode));
    				l->length = p->length - len;
    				l->address = p->address + len;
    				l->state = 0;
    				l->number = 0;
    				l->next = p->next;
    				p->next = l;
    				p->length = len;
    				p->number = num;
    				p->state = 1;
    				printf("内存分配成功!\n");
    				return;
    			}
    			else if (p->length == len) {
    				//刚刚好够分配,只要修改作业编号和内存块状态即可
    				p->number = num;
    				p->state = 1;
    				printf("内存分配成功!\n");
    				return;
    			}
    		}
    		p = p->next;
    	}
    	printf("内存分配失败,没有找到合适的空闲内存块\n");
    }
    
    //打印
    void print(pLNode L) {
    	printf("************************************************************\n");
    	printf("内存分配情况如下:\n");
    	printf("起始地址\t内存块长度\t存放作业编号\t内存块状态\n");
    	pLNode p = L;
    	while (p != NULL) {
    		printf("%8d\t%10d\t", p->address, p->length);
    		if (p->number == 65535) {
    			printf("    操作系统\t");
    		}
    		else if (p->number == 0) {
    			printf("      无作业\t");
    		}
    		else {
    			printf("%12d\t", p->number);
    		}
    		if (p->state == 0) {
    			printf("      空闲\n");
    		}
    		else {
    			printf("    已分配\n");
    		}
    		p = p->next;
    	}
    	printf("************************************************************\n");
    }
    
    //服务选择菜单
    int select() {
    	int a;
    	printf("************************************************************\n");
    	printf("请选择服务:\n");
    	printf("1.为新作业分配内存\t2.撤销作业\n3.查看内存分配情况\t4.退出\n");
    	printf("请输入编号以选择:");
    	scanf("%d", &a);
    	return a;
    	printf("************************************************************\n");
    }
    
    int main()
    {
    	pLNode L = (pLNode)malloc(sizeof(LNode));
    	InitLNode(L, 512);
    	int a;
    	int len, num;
    	a = select();
    	getchar();
    	while (a != 4) {
    		switch (a) {
    		case 1:
    			printf("请输入要分配内存的作业的长度和编号:");
    			scanf("%d%d", &len, &num);
    			Allocation(L, len, num);
    			break;
    		case 2:
    			printf("请输入要撤销作业的编号:");
    			scanf("%d", &num);
    			Revocation(L, num);
    			break;
    		case 3:
    			//system("cls");
    			print(L);
    			break;
    		default:
    			break;
    		}
    		a = select();
    	}
        return 0;
    }
    
    调试结果:


    展开全文
  • 刚在浏览帖子的时候,看到这个帖子,对内存分配的原理讲得很透彻,看了一遍,还未理解透彻,特收藏下来,以后慢慢回味!   现象 1 压力测试过程中,发现被测对象性能不够理想,具体表现为:  进程的系统态CPU...

        刚在浏览帖子的时候,看到这个帖子,对内存分配的原理讲得很透彻,看了一遍,还未理解透彻,特收藏下来,以后慢慢回味!

     

    现象
    1 压力测试过程中,发现被测对象性能不够理想,具体表现为: 
    进程的系统态CPU消耗20,用户态CPU消耗10,系统idle大约70 
    2 用ps -o majflt,minflt -C program命令查看,发现majflt每秒增量为0,而minflt每秒增量大于10000。

    初步分析
    majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误。
    这两个数值表示一个进程自启动以来所发生的缺页中断的次数。
    当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作: 
    检查要访问的虚拟地址是否合法 
    查找/分配一个物理页 
    填充物理页内容(读取磁盘,或者直接置0,或者啥也不干) 
    建立映射关系(虚拟地址到物理地址) 
    重新执行发生缺页中断的那条指令 
    如果第3步,需要读取磁盘,那么这次缺页中断就是majflt,否则就是minflt。 
    此进程minflt如此之高,一秒10000多次,不得不怀疑它跟进程内核态cpu消耗大有很大关系。

    分析代码
    查看代码,发现是这么写的:一个请求来,用malloc分配2M内存,请求结束后free这块内存。看日志,发现分配内存语句耗时10us,平均一条请求处理耗时1000us 。 原因已找到! 
    虽然分配内存语句的耗时在一条处理请求中耗时比重不大,但是这条语句严重影响了性能。要解释清楚原因,需要先了解一下内存分配的原理。 

    内存分配的原理
    从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中(一般是堆和栈中间)找一块空闲的。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。 
    在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。 
    下面以一个例子来说明内存分配的原理:
              
    1进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。其中,mmap内存映射文件是在堆和栈的中间(例如libc-2.2.93.so,其它数据文件等),为了简单起见,省略了内存映射文件。_edata指针(glibc里面定义)指向数据段的最高地址。 
    2进程调用A=malloc(30K)以后,内存空间如图2:malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。你可能会问:只要把_edata+30K就完成内存分配了?事实是这样的,_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。 
    3进程调用B=malloc(40K)以后,内存空间如图3. 

             
    4进程调用C=malloc(200K)以后,内存空间如图4:默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。这样子做主要是因为brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的),而mmap分配的内存可以单独释放。当然,还有其它的好处,也有坏处,再具体下去,有兴趣的同学可以去看glibc里面malloc的代码了。 
    5进程调用D=malloc(100K)以后,内存空间如图5. 
    6进程调用free(C)以后,C对应的虚拟内存和物理内存一起释放 
             

    7进程调用free(B)以后,如图7所示。B对应的虚拟内存和物理内存都没有释放,因为只有一个_edata指针,如果往回推,那么D这块内存怎么办呢?当然,B这块内存,是可以重用的,如果这个时候再来一个40K的请求,那么malloc很可能就把B这块内存返回回去了。 
    8进程调用free(D)以后,如图8所示。B和D连接起来,变成一块140K的空闲内存。 
    9默认情况下:当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)。在上一个步骤free的时候,发现最高地址空闲内存超过128K,于是内存紧缩,变成图9所示。

    真相大白
    说完内存分配的原理,那么被测模块在内核态cpu消耗高的原因就很清楚了:每次请求来都malloc一块2M的内存,默认情况下,malloc调用mmap分配内存,请求结束的时候,调用munmap释放内存。假设每个请求需要6个物理页,那么每个请求就会产生6个缺页中断,在2000的压力下,每秒就产生了10000多次缺页中断,这些缺页中断不需要读取磁盘解决,所以叫做minflt;缺页中断在内核态执行,因此进程的内核态cpu消耗很大。缺页中断分散在整个请求的处理过程中,所以表现为分配语句耗时(10us)相对于整条请求的处理时间(1000us)比重很小。

    解决办法
    将动态内存改为静态分配,或者启动的时候,用malloc为每个线程分配,然后保存在threaddata里面。但是,由于这个模块的特殊性,静态分配,或者启动时候分配都不可行。另外,Linux下默认栈的大小限制是10M,如果在栈上分配几M的内存,有风险。 
    禁止malloc调用mmap分配内存,禁止内存紧缩。
    在进程启动时候,加入以下两行代码:
    mallopt(M_MMAP_MAX, 0);         // 禁止malloc调用mmap分配内存
    mallopt(M_TRIM_THRESHOLD, -1);  // 禁止内存紧缩
    效果:加入这两行代码以后,用ps命令观察,压力稳定以后,majlt和minflt都为0。进程的系统态cpu从20降到10。

    小结
    可以用命令ps -o majflt minflt -C program来查看进程的majflt, minflt的值,这两个值都是累加值,从进程启动开始累加。在对高性能要求的程序做压力测试的时候,我们可以多关注一下这两个值。 
    如果一个进程使用了mmap将很大的数据文件映射到进程的虚拟地址空间,我们需要重点关注majflt的值,因为相比minflt,majflt对于性能的损害是致命的,随机读一次磁盘的耗时数量级在几个毫秒,而minflt只有在大量的时候才会对性能产生影响。

    展开全文
  • 关于操作系统内存分配调用的讨论

    万次阅读 2004-06-30 06:35:00
    原文是: 发信人: true (对自己更残酷一点), 信区: C_and_CPP标 题: new出来的空间系统会不会自动回收?发信站: 哈工大紫丁香 (Fri May 14 12:07:43 2004), 转信当程序运行完之后,我觉得系统应该会自动回收才对,...
  • 操作系统 内存分配与回收 实验报告 操作系统 内存分配与回收 实验报告 操作系统 内存分配与回收 实验报告
  • 文章目录一、连续内存分配1、内存碎片的问题(1)外部碎片(2)内部碎片2、连续内存分配算法(1)首次适配(2)最优适配(3)最差适配3、碎片整理方法4、连续内存分配的缺点二、非连续内存分配1、非连续分配的优点2...
  • 内存分配程序操作系统大作业内存分配程序操作系统大作业内存分配程序操作系统大作业
  • 连续内存分配 碎片整理 e.g: 伙伴系统(Buddy System) 计算机内存管理概述 首先我们知道计算机的内存是分很多层次的,不同层次之间访存速度相差很大,(甚至达到几个数量级) MMU 工作原理介绍 W...
  • 伙伴系统内存分配浅析

    千次阅读 2013-09-22 15:10:43
    最近在网上看到一篇关于伙伴系统内存分配问题比较好的文章。这里分享过来供大家参考。 原文地址:http://blog.csdn.net/vanbreaker/article/details/7605367 伙伴系统的概述  Linux内核内存管理的一项重要工作...
  • 前一段时间查看资料得知内存管理的算法大致有两种:内存分配算法、内存页面置换算法,对这些算法虽然可能不需要实现,但是需要了解其中的概念原理,以备不时之需。 内存分配的算法主要有5种: 第一种是固定内存分配...
  • 操作系统——内存分配管理

    千次阅读 2019-08-29 15:39:51
    1. 连续分配 1.1 单一连续分配 1.2 固定分区分配 1.3 动态分区分配 2. 非连续分配 2.1 基本分页存储管理方式 2.2 基本分段存储管理方式 2.3 段页式存储管理方式
  • 在操作系统中,内存管理的目的是什么呢? 其中最主要的就是提高内存的利用率,所谓的提高内存利用率,就是尽可能的在内存中多存储进程,这就涉及到为进程分配内存空间了。分配的方式主要是有两种——连续分配和离散...
  • 在linux操作系统下模拟linux操作系统内存管理以及分配,学习操作系统内存管理以及分配,代码用c++示例。
  • 操作系统原理:动态内存分配

    千次阅读 2017-04-12 23:21:13
    动态内存分配背后的机制深刻的体现了计算机科学中的这句名言: All problem in CS can be solved by another level of indirection. — Butler Lampson ...
  • 操作系统 内存分配与回收

    千次阅读 2018-11-28 17:23:14
    操作系统 内存分配与回收 无论什么进程,想要运行的就需要申请内存的空间,操作系统把我们的内存空间分割成化成一个个页表, 现在的一般一个页表的大小是4kb,而每个进程申请的空间都是以页为单位的。 比如我们...
  • 操作系统内存管理内存空间的连续分配方式1.概述、分类内存空间的连续分配方式,是指为一个用户程序(作业)分配一个连续的内存空间。 按照内存空间划分方式的不同可将连续分配方式划分为以下四种方式: 1. 单一...
  • 内存与操作系统内存管理

    千次阅读 2021-02-28 15:10:12
    文章目录内存与操作系统内存管理一、内存的基础知识二、内存管理2.1 内存空间扩充2.2 内存空间的分配与回收 一、内存的基础知识   内存是用于存放数据的硬件,程序执行前需要将数据放入内存中才能被CPU处理。内存...
  • 操作系统分配内存

    千次阅读 2016-07-05 14:01:26
    操作系统内存的最小访问单位是 字节 ,也就是8bit。 通常我们所说的计算机系统是32位的总线,所谓的32位总线就是说一次读写可以从内存当中读或者写32位(也就是4字节)。 因为一次读写是32位,所以需要...
  • vxWorks中对于系统内存分配。 在mips架构上,也就是对c0000000以上地址的分配: 1,没有rpt任务支持时: 2,有rpt任务支持时:
  • 3.1.4 操作系统内存分配与回收

    千次阅读 多人点赞 2020-04-23 21:32:09
    动态分区分配(可变分区分配)(1)系统要用怎样的数据结构记录内存的使用情况呢?(2)当多个空闲分区都能满足要求时,应该选择哪个分区进行分配?(3)如何进行分区的分配和回收操作?4.内部碎片与外部碎片 0....
  • 一种嵌入式系统内存分配方案

    千次阅读 2015-03-20 09:48:04
    1 嵌入式系统中对内存分配的要求 ①快速性。嵌入式系统中对实时性的保证,要求内存分配过程要尽可能地快。因此在嵌入式系统中,不可能采用通用操作系统中复杂而完善的内存分配策略,一般都采用简单、快速的内存...
  • contiki系统分析四:内存分配

    千次阅读 2013-03-25 17:49:05
    contiki有三种分配内存的方式。...标准C库的malloc的栈内存分配器,在contiki这种受限系统中使有最危险。 memb的内存分配器 有下列的API:  MEMB(name, structure, num) : 定义memory block. void memb
  • 上一篇:操作系统from清华大学向勇,陈渝 笔记(二)操作系统的启动、中断、异常、系统调用 3-1 计算机体系结构&内存分层体系 3-2地址空间和地址生成 3-3连续内存分配内存碎片与分区的动态分配 3-4 连续内存...
  • 连续内存分配与非连续内存分配

    千次阅读 2018-09-22 08:45:03
    连续内存分配 首次适配:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。 最优适配:空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区。 最坏适配:空闲...
  • 详解操作系统分配内存

    万次阅读 多人点赞 2017-07-08 16:37:29
    操作系统内存的最小访问单位是 字节 ,也就是8bit。 通常我们所说的计算机系统是32位的总线,所谓的32位总线就是说一次读写可以从内存当中读或者写32位(也就是4字节)。 因为一次读写是32位,所以需要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,045,037
精华内容 418,014
关键字:

系统内存分布