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陷阱与缺陷

查看全文
  • 相关阅读:
    【Java EE 学习 81】【CXF框架】【CXF整合Spring】
    【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】
    【Java EE 学习 80 上】【WebService】
    【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】
    【Java EE 学习 79 上】【mybatis 基本使用方法】
    【Java EE 学习 78 下】【数据采集系统第十天】【数据采集系统完成】
    【Java EE 学习 78 中】【数据采集系统第十天】【Spring远程调用】
    【Java EE 学习 78 上】【数据采集系统第十天】【Service使用Spring缓存模块】
    【Java EE 学习 77 下】【数据采集系统第九天】【使用spring实现答案水平分库】【未解决问题:分库查询问题】
    【Java EE 学习 77 上】【数据采集系统第九天】【通过AOP实现日志管理】【通过Spring石英调度动态生成日志表】【日志分表和查询】
  • 原文地址:https://www.cnblogs.com/warm-home/p/12832667.html
  • Copyright © 2011-2022 走看看