zoukankan      html  css  js  c++  java
  • c/c++内存笔记

    C/C++内存笔记

    c/c++笔记

    内存占用

    1. 栈区(stack):普通局部变量,由编译器自动分配和释放,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等,其操作类似于数据结构中的栈。
    2. 堆区(heap):一般由程序员自动分配,如果程序员没有释放,程序正在运行时不会被自动释放,程序结束时由操作系统回收,其分配类似于链表。
    3. 全局区(静态static):存放全局变量,静态数据,常量,程序结束后系统释放;全局区分配已初始化的全局区(data)和未初始化的全局区(bss)。常量区存放常量支付串,程序结束后由系统释放。
    4. 代码区:存放函数体(类成员函数和全局区)的二进制代码。

    内存分配方式

    1. 从静态存储区分配
      内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
    2. 在栈上创建
      在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时,这些内存单元会自动被释放。
      栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存容量有限。
    3. 从堆上分配
      亦称为动态内存分配。
      程序在运行的时候使用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生命周期有程序员决定,使用非常灵活,但如果在堆上分配了空间,既有责任回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生内存碎片。

    操作系统内存管理

    内存一直是计算机系统中最宝贵而又最紧俏的资源,内存能否被有效、合理的使用,将直接影响到操作系统的性能。

    管理内存的目的:

    一是方便用户使用;
    二是提高存储器的利用率。

    内存管理能力:

    1. 内存空间的分配与回收
    2. 地址转换,将逻辑地址转换为物理地址
    3. 存储保护和存储共享
    4. 内存空间的扩充

    存放区域示例:

    #include <stdio.h> 
    #include <stdlib.h> 
    int iNUM = 250;     //全局区(静态区,已初始化) 
    int main(int argc, char** argv) {
        int iNUM1 ;             //栈区 
        char cNUM3[] = "ABC" ;  //栈区
        char *cP ;              //栈区
        char *cP1 = "888888"  ; //cP1在栈区,888888在常量区 
        cP = (char*)malloc(20) ;//堆区 
        static int iNUM2 = 100 ;//全局区(静态区,已初始化) 
        return 0;
    }
    

    一个程序的内存分区

    在程序没有执行前,有几个内存分区已经确定,注意:分区确定但没有加载到内存,程序只有在运行时候才加载到内存:
    text(代码区):通常只读;存放函数
    data:已经初始化的数据,全局变量,static变量,文字常量区(只读)
    bss:没有初始化的数据,全局变量,static变量

    当运行程序时,加载内存,首先根据上面确定的3个分区(text,data,bss)先加载,然后额外加载stack(栈区),heap(堆区)

    栈越界

    即栈区空间使用完,超出栈的使用返回,导致段错误,学习时一般程序不会出现栈越界,一般是在使用函数递归的时候可能会出现栈越界。

    堆越界一种情况(内存污染)

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h>
    int main(int argc, char** argv) {
        char *p = NULL ;
        p = (char*)malloc(0) ;
        if(p == NULL){
            printf("分配错误
    ") ;
        } 
        strcpy(p,"nihao") ;
        printf("%s 
    ",p) ;
        return 0;
    }
    

    这个程序能够运行出来,但我们能够明显知道代码是错的,但是它能够运行,造成了内存的污染。但是如果我们在return前面free(p)的话就会程序崩溃但他不是free错误,只是你之前没有malloc正确而已。

    指针指向栈区空间

    int main(){
        int *p ;
        *P = 10 ;
        printf("*p = %d 
    ",*p) ;
        return 0 ;
    }
    

    对于这个段函数来说,会出现段错误。因为p指针没有指向,p指针是一个野指针。
    解决方式:

    //在第二行后面添加
    int a ; //定义一个栈区的变量
    p = &a ; //指针指向栈区空间
    

    指针指向堆区空间

    int main(){
        int *p ;
        *P = 10 ;
        printf("*P = %d 
    ",*P) ;
        return 0;
    }
    

    同样的是这段错误的代码,我们使用另一种方式修改它。

    //还是在第二行后面添加
    //使用malloc函数在堆区申请一段内存
    p = malloc(sizeof(int)) ;
    //在c++里面需要对malloc申请的内存强转
    //p = (int *)malloc(sizeof(int)) ;
    if(p == NULL){
        printf("内存空间分配失败") ;
        return -1 ;
    }
    

    //然后在return 0 之前添加释放函数
    free(p) ;

    提示:malloc动态申请的堆区内存空间不会自动释放,使用完后需要free释放。同一块内存空间只能释放一次。


    更多内容等待添加...

    参考书籍推荐:


    1、C和指针
    2、C专家编程
    3、C陷阱与缺陷

查看全文
  • 相关阅读:
    【竞赛笔记】飞思卡尔智能车竞赛
    【实习笔记】智能广场健身设备总结
    RabbitMQ之安装
    数据结构与算法之队列
    joda-time时间操作组件
    JavaScript中的跨域问题
    数据结构与算法之链表
    Jedis集成到项目中
    ICMP协议和ping命令
    jedis的使用
  • 原文地址:https://www.cnblogs.com/warm-home/p/12832667.html
  • Copyright © 2011-2022 走看看