美文网首页
10-内存空间的布局

10-内存空间的布局

作者: ducktobey | 来源:发表于2019-11-10 23:28 被阅读0次

内存空间的布局

每个应用都有自己独立的内存空间,其内存空间一般都有以下几大区域

  1. 代码段(代码区)
    • 用来存放代码
    • 只读
  2. 数据段(全局区)
    • 用于存放全局变量
  3. 栈空间
    • 每调用一个函数,就会为函数分配一段连续的栈空间,等函数调用完毕后,会自动回收这段栈空间
    • 自动分配和回收
  4. 堆空间
    • 需要主动申请和释放

所以,某应用的内存空间(主要),可以通过下图来进行表示

通过前面的介绍,已经知道,如果是函数调用,局部变量,使用的是栈空间,如果该变量,是所有人都可以访问的,可以使用全局区,编写的代码,存放在代码区。那堆空间有什么用呢?

堆空间

在程序运行过程中,为了能够自由控制内存的生命周期大小,会经常使用堆空间的内存。

所以在C++中,可以通过下面的方式,来申请\释放内存

  1. malloc \ free
    例如现在向堆空间申请4个字节的存储空间。然后将申请的内存空间,用来存放int变量。然后就可以往申请的空间中存放数据了。然后使用完了以后,使用free来回收申请的堆空间内存。需要注意:在释放内存时,请不要过度释放

    int* p = (int *)malloc(4);
    *p = 10;
    free(p);
    

    其中指针与申请堆空间内存的关系如下(地址值仅供参考,X86环境 32bit)

下面两种申请堆空间内存的区别

int* p = (int*)malloc(4);
char* p = (char*)malloc(4);
  1. int 这种申请方式,在堆空间中申请了4个直接的内存空间,并且最后是使用的int类型来指向该空间,后面再访问该内存空间时,就会按照int的寻址大小来进行访问,可以访问4个字节。

  2. char这种申请方式,虽然在堆空间申请了4个直接的内存空间,但是使用的是char类型来指向该空间,由于char类型的寻址范围是1字节,所以char类型的指针只能访问堆空间中的第一个字节。

  3. new\delete

    int* p = new int;
    *p = 10;
    delete p;
    
  4. new[]\delete[]

    int* p = new int[];
    *p = 10;
    delete[] p;
    

堆空间申请注意点:

  1. 申请堆空间成功后,会返回那一段内存空间的地址
  2. 申请和释放必须是1对1的关系,不然可能会存在内存泄漏

现在的很多高级编程语言不需要开发人员去管理内存(比如Java),屏蔽了很多内存细节,利弊同时存在。

  • 利:提高开发效率,避免内存使用不当或泄漏
  • 弊:不利于开发人员了解本质,永远停留在API调用和表层语法糖,对性能优化无从下手

堆空间的初始化

假设现在有这样一段代码

int* p = (int*)malloc(4);

当申请完内存以后,堆空间有没有将内存进行初始化呢?如果现在在visual studio里面去访问指针指向的存储空间的话,会发现结果是一堆乱七八糟的值,所以在visual studio里面,是没有初始化的。如果这个时候,想在申请完堆空间以后,就初始化堆空间中的内存,可以使用下面的这种方式来初始化

int size = sizeof(int) * 10;
int* p1 = (int*)malloc(size);
int* p2 = (int*)malloc(size);
memset(p2, 0, size);

通过这种方式,就可以将*p2的每一个字节都初始化为0,但是由于上面没有对 *p1进行初始化,所以 *p1没有被初始化。

初始化总结:

int* p1 = new int;          //未被初始化
int* p2 = new int();        //被初始化为0
int* p3 = new int(5);       //被初始化为5
int* p4 = new int[3];       //数组元素未被初始化
int* p5 = new int[3]();     //3个数组元素都被初始化为0
int* p6 = new int[3]{};     //3个数组元素都被初始化为0
int* p7 = new int[3]{5};    //数组首元素被初始化为5,其他元素被初始化为0
memset的作用

memset函数是将较大数据结构(比如对象,数组等)内存清零的比较快的方法。

比如现在有一个如下的Person对象,需要对对象中的每个成员变量都清零的话,就可以使用memset来快速清零。

struct Person {
    int m_id;
    int m_age;
    int m_height;
};

void func(){
    Person person;
    person.m_id = 1;
    person.m_age = 20;
    person.m_height = 190;
    memset(&person, 0, sizeof(person));
    
    Person persons[] = { {1,20,190},{1,18,180} };
    memset(persons, 0, sizeof(persons));
}

对象的内存

一个对象被创建出来以后,可以存在于3个地方

  • 全局区(数据段):全局变量
  • 栈空间:函数里面的局部变量
  • 堆空间:动态申请内存(malloc,new等)

如下代码所示:

//全局区
Person g_person;

int main() {
    //栈空间
    Person person;
    //堆空间
    Person* p = new Person;
    return 0;
}

所以,通过本文的讲解,对内存有更深的理解了吗?

demo下载地址

文章完。

相关文章

  • 10-内存空间的布局

    内存空间的布局 每个应用都有自己独立的内存空间,其内存空间一般都有以下几大区域 代码段(代码区)用来存放代码只读 ...

  • 10-内存空间布局

    写在前面 名词解释 码上建功 --堆空间 码说 --栈空间 全局区 装逼一下 完整代码demo,请移步GitHub...

  • 进程所使用的内存空间

    进程的内存空间布局 Kernel space:内核态内存空间,用户代码无法读写,否则会导致“段错误”的异常 Ran...

  • Android API version 10->23+

    Android API version 10->23+ Android API version 10->23+

  • 任务10-常见布局问题

    1. 浮动元素有什么特征?对父容器、其他浮动元素、普通元素、文字分别有什么影响? 1.1 特征 1.1-1. ...

  • 记录一下时间都做了那些事情

    14:10- :读书。

  • 深入理解golang 的栈

    线程栈(thread stacks)介绍 先回顾下linux的内存空间布局 当启动一个C实现的thread时,C标...

  • 从C++探究汇编.06

    封装 成员变量私有化,提供公共的getter和seter给外界去访问成员变量 内存空间的布局 每个应用都有自己独立...

  • Category分类

    一、分类 扩展(extension)类的一部分编译时期加载隐藏类的私有属性对象的内存布局确定(内存空间、结构体) ...

  • iOS内存布局&内存管理方案&数据结构

    内存布局 上面的图代表一个内存区域,内存区域分为内核区的内存(最上边),程序加载的控件(中间),保留的内存空间(最...

网友评论

      本文标题:10-内存空间的布局

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