内存的管理方式

1、内存的区域

    对于内存的区域划分上,不同的区域划分上都各有不同。

划分1:

代码区、堆、栈、 全局区(静态存储区)、 文字常量区、

划分2:

代码段、堆、栈、  data段、BSS段、文字常量区

全局区:

    又成为静态存存储区。保存的是全局变量和静态变量(带有static 关键字)。全局区分为两个区域:一个区域保存的是经过初始化,且初始化的值不为零的全部变量和静态变量;一个区域保存的是没有经过初始化或者初始化的值为零的。程序结束由 OS 进行释放

常量区:

    将一些不可以被更改的只读的常量进行保存的区域。比如文字字符串等。程序结束之后由系统释放。

代码区:

    保存的是二进制代码的区域。

堆:

    由程序猿手动 malloc/free进行开辟的空间,一般也是由程序猿调用 free/delete 进行释放,即使没有进行释放,也可以由 OS 进行释放。

栈:

    程序运行的时候由编系统进行分配,存在函数的的局部变量等。程序结束由系统自动释放。

DATA段:

    有经过初始化的全局变量和静态变量存储的区域,当然初始值不能为零

BSS段:

    保存的是没有经过初始化的全局变量和静态变量存储的区域,或者经过初始化但是初始值为零的也保存在这个区域。

注意:很显然,DATA 段和 BSS 段的也行,其实就是全局区(静态存储器)内部之一,DATA 段和 BSS 段只不过是全局区更加精细的划分。

解释:

    借助前人总结的知识:


int a = 0;            全局初始化区
char *p1;          全局未初始化区
main()
{
  int b;                          // 栈
  char s[] = "abc";      //栈
  char *p2;                  //栈
  char *p3 = "123456";          //"123456/0"在常量区,p3在栈上。
  static int c =0;                    //全局(静态)初始化区
  p1 = (char *)malloc(10);
  p2 = (char *)malloc(20);
                                                //分配得来得10和20字节的区域就在堆区。
  strcpy(p1, "123456");         // 123456 放在常量区,编译器可能会将它与p3所指向的"123456"                              //优化成一个地方。
}

 

2、内存的三种来源:栈、堆、全局区

栈:

    (1)运行时候由编译器自动分配自动回收,这一切都是自动的,程序猿不用管理

    (2)反复使用:每一个进程,操作系统都会为这个进程分配栈,这个进程不论是怎么出入栈,都是在这个栈,反复使用。

    (3)脏内存:栈内存由于反复的使用,程序使用完毕之后不会去做清理的工作,所以重新使用栈的时候,值就是脏的。

    (4)临时性:局部变量的出栈入栈,每次都是不一样,所以都是临时性的,所以,绝对不要返回栈变量的指针,因为栈地址都是临时的,

    (5)栈溢出:因为栈的大小是操作系统设定的,当出现无线递归或者出现巨大的局部变量。

堆:

    (1)大块内存:栈的空间非常有限,所以当需要需要大块内存的时候,就在堆进行申请,

    (2)手动申请、释放: 使用 malloc/new 申请,free/delete 进行释放。

    (3)脏内存 : 堆内存也是被反复使用的

malloc 实际应用:

    操作系统会对空闲的内存块进行组织管理,而这种组织管理的方式是以链表的形式。当程序猿调用 malloc 的时候就从空闲的链表找出一块大小满足申请要求的空间(可以比用户申请的大),然后将这个内存空间一分为二:一部分是用户申请空间的大小,另外的部分是维护链表这个节点的基本信息(比如地址、块内存的大小)。所以当 malloc 的时候,不论申请的空间是多大,都必须申请一块用于维护链表的空间。


#include <stdio.h>
#include<stdlib.h>
int main(void)
{
    int i,j;
     FILE * fp = fopen("qxj511.txt", "w");
    for ( i = 0; i < 2048; i++)
    {
        int *p1 = (int *)malloc(i);
        int *p2 = (int *)malloc(i);

        fprintf(fp, "i =%d : p1 = %d, p2 = %d,\n",i, p1, p2);
        free(p1);
        free(p2);
    }
    fclose(fp); /*关闭文件*/
}

    在 gcc 的编译器下面做的测试,


i =0 : p1 = 151765360, p2 = 151765376,    // 1
i =1 : p1 = 151765376, p2 = 151765360,
i =2 : p1 = 151765360, p2 = 151765376,
i =3 : p1 = 151765376, p2 = 151765360,
i =4 : p1 = 151765360, p2 = 151765376,
i =5 : p1 = 151765376, p2 = 151765360,
i =6 : p1 = 151765360, p2 = 151765376,
i =7 : p1 = 151765376, p2 = 151765360,
i =8 : p1 = 151765360, p2 = 151765376,
i =9 : p1 = 151765376, p2 = 151765360,
i =10 : p1 = 151765360, p2 = 151765376,
i =11 : p1 = 151765376, p2 = 151765360,
i =12 : p1 = 151765360, p2 = 151765376, // 1
i =13 : p1 = 151765392, p2 = 151765416, // 2
i =14 : p1 = 151765416, p2 = 151765392,
i =15 : p1 = 151765392, p2 = 151765416,
i =16 : p1 = 151765416, p2 = 151765392,
i =17 : p1 = 151765392, p2 = 151765416,
i =18 : p1 = 151765416, p2 = 151765392,
i =19 : p1 = 151765392, p2 = 151765416,
i =20 : p1 = 151765416, p2 = 151765392,
i =21 : p1 = 151765440, p2 = 151765472,
i =22 : p1 = 151765472, p2 = 151765440, // 2
。。。。。。。

    经过笔者的测试,当 申请的的空间,从零到12个字节的时候,两者的差是16个字节,后序申请的全部的空间差是 8 个字节。也就是说,实际申请的空间是链表头部 + 申请的空间,同时,8 个字节是处于内存对齐。

参考 : http://blog.csdn.net/misskissc/article/details/17717717

    (1)malloc(0) :


If size is  0,  thenmalloc()  returns either NULL, or a unique pointer value that can later be successfully passed to free().

根据官方的解释,当申请的空间为零的时候,返回值要么是为 NULL,要么就可以正确返回一个地址,这个地址被正确释放。但是实际上,都是返回后者。

    根据 malloc 的实现方式,虽然申请的空间为零,但是链表的指针也是会被申请一段空间的,所以可以正确申请,空间为 16 字节(maybe 8字节) + 0; 而这个链表指针地址其实就是 malloc 的返回值的地址。

注意: 对于链表维护空间的大小是16 字节,这个是不确定的,有人说是8个字节,

malloc 与 sizeof:

    使用 malloc 是申请了一个程序猿指定的空间,返回值是指向这段空间的的首地址。想要计算这段申请空间的大小,是不可以通过 sizeof 计算出来的:


int *p = (int *)malloc(10 * sizeof(int));
printf("%d\n", sizeof(p));

 

打印出来:

等于4

    原因分析,p 是指向申请空间的首地址,也就是说这个是地址,对于指针来说,不论指向的空间是多大,指针占据的就是四个字节。所以,sizeof 是不能计算 malloc。

时间: 2024-09-28 12:40:10

内存的管理方式的相关文章

ARC下面的Block对内存的管理方式

一.问题引入 近日开发中引入一个随机crash,Crash堆栈如下: Exception Type: SIGSEGV Exception Codes: SEGV_ACCERR at 0x0000000101850148 Crashed Thread: 0 Thread 0 Crashed: 0 libobjc.A.dylib 0x00000001802601a0 objc_retain + 16 1 CoreFoundation 0x0000000180f593a0 -[__NSDictiona

内存连续分配管理方式

内存连续分配方式,是指为一个用户程序分配一个连续的内存空间.它主要包括单一连续分配.固定分区分配和动态分区分配. 单一连续分配 内存在此方式下分为系统区和用户区,系统区仅提供给操作系统使用,通常在低地址部分:用户区是为用户提供的.除系统区之外的内存空间.这种方式无需进行内存保护. 这种方式的优点是简单.无外部碎片,不需要额外的技术支持.缺点是只能用于单用户.单任务的操作系统中,有内部碎片,存储器的利用率极低. 固定分区分配 固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若

操作系统--内存管理方式

“碎片的内存”描述一个系统中所有不可用的空闲内存.这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用.这一问题通常都会发生,原因在于空闲内存以小而不连续方式出现在不同的位置.由于分 配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色. internal fragmentation:when memory allocated to a process is larger than requested memory, the differe

glusterfs 内存管理方式

glusterfs中的内存管理方式: 1 struct mem_pool * 2 mem_pool_new_fn (unsigned long sizeof_type, 3 unsigned long count, char *name) 4 { 5 struct mem_pool *mem_pool = NULL; 6 unsigned long padded_sizeof_type = 0; 7 void *pool = NULL; 8 int i = 0; 9 int ret = 0; 1

十天学Linux内核之第三天---内存管理方式

昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内存和内核的可用内存,还会讲到内核对内存分类的方式以及如何决定分配和释放内存,内存管理是应用程序通过软硬件协助来访问内存的一种方式,这里我们主要是介绍操作系统正常运行对内存的管理.插个话题,刚才和姐姐聊天,她快结婚了,说起了自己的初恋,可能是一句很搞笑的话,防火防盗防初恋,,嘎嘎,这个好像是的吧,尽管

内存非连续分配管理方式

非连续分配允许一个程序分散地装入到不相邻的内存分区中,根据分区的大小是否固定分为分页存储管理方式和分段存储管理方式. 基本分页存储管理方式 固定分区会产生内部碎片,动态分区会产生外部碎片,这两种技术对内存的利用率都比较低.我们希望内存的使用能尽量避免碎片的产生,这就引入了分页的思想:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位.每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间. 分页的方法从形式上看,像分区相等的固定分区技术,分页管理不会产生外部

windows内存管理方式以及优缺点

Windows内存管理方式:页式管理,段式管理,段页式管理 页式管理 将各进程的虚拟空间(逻辑地址)划分为若干个长度相等的页,业内管理把内存空间(物理内存)按照页的大小划分为片或者页面,从而实现了离散分配,然后把页式虚拟地址和内存地址建立一一对应的页表,并用相应的硬件地址变换机构来解决离散地址变化问题,(程序加载时,可将任意一页放入内存中任意一个页框而且这些页框不必连续,从而实现了离散分配)页式管理采用请求调页或预调页技术来实现内外存存储器的统一管理,地址结构由两部分构成,页号+页内地址 其优点

内存管理-基本分页管理方式

在存储器管理中,连续分配方式会形成许多"碎片",虽然可通过"紧凑"方法将许多碎片拼接成可用的大块空间,但须为之付出很大开销.如果允许将一个进程直接分散地装入到许多不相邻的分区中,则无须再进行"紧凑".基于这一思想而产生了离散分配方式.如果离散分配的基本单位是页,则称为分页存储管理方式.在分页存储管理方式中,如果不具备页面对换功能,则称为基本分页存储管理方式,或称为纯分页存储管理方式,它不具有支持实现虚拟存储器的功能,它要求把每个作业全部装入内存后

ESXi主机管理内存资源的方式

因为内存通常是最有限的资源,ESXi采用内存过量配置(Memory overcommitment,即配置后的虚拟机内存可能超过物理内存(RAM))对内存进行管理.使用内存过量配置时,ESXi必须使用技术从一个或多个VM中回收内存,这些技术被称为:透明页面共享(Transparent Page Sharing,TPS).气球(ballooning).交换(swap)和内存压缩(Memory compression). 1.  透明页面共享 ESXi主机运行相同操作系统的VM时,保存一个可能相同的内