精华内容
下载资源
问答
  • 对于局部变量,如果是基本类型,会把值直接存储在栈;如果是引用类型,比如String s = new String("william");会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。 再如 String s1 = new String(“william”)...
    对于局部变量,如果是基本类型,会把值直接存储在栈;如果是引用类型,比如String s = new String("william");会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。
    再如
    String s1 = new String(“william”);
    String s2 = s1;
    s1和s2同为这个字符串对象的实例,但是对象只有一个,存储在堆,而这两个引用存储在栈中。
    
    类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中),基本类型和引用类型的成员变量都在这个对象的空间中,作为一个整体存储在堆。而类的方法却是
    该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。
    展开全文
  • 局部变量内存分配可能在栈上也可能在堆的简单说明: 1.(操作系统):由操作系统自动分配释放 2.(操作系统): 一般由程序员分配释放,例如c/c++中,golang,java,python有自动的垃圾回收机制 ...
  • 1、区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是一块连续的...

    一、预备知识—程序的内存分配 

    一个由c/C++编译的程序占用的内存分为以下几个部分 
    1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存。 
    2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的.一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放。 
    3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 
    4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 
    5、程序代码区—存放函数体的二进制代码。

     

    二、例子程序 
    这是一个前辈写的,非常详细 

    //main.cpp
    
    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/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
    
    }
    
    

    三、堆和栈的理论知识 
    3.1申请方式 
    stack: 
    由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 
    heap: 
    需要程序员自己申请,并指明大小,在c中malloc函数 
    如p1 = (char *)malloc(10); 
    在C++中用new运算符 
    如p2 = (char *)malloc(10); 
    但是注意p1、p2本身是在栈中的。 
    3.2 申请后系统的响应 
    栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 
    堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 
    会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 
    3.3申请大小的限制 
    栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 
    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 
    3.4申请效率的比较: 
    栈由系统自动分配,速度较快。但程序员是无法控制的。 
    堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 
    另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活 
    3.5堆和栈中的存储内容 
    栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 
    当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 
    堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 
    3.6存取效率的比较

    char s1[] = "aaaaaaaaaaaaaaa"; 
    char *s2 = "bbbbbbbbbbbbbbbbb"; 
    aaaaaaaaaaa是在运行时刻赋值的; 
    而bbbbbbbbbbb是在编译时就确定的; 
    但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。 
    比如:

    #include <stdio.h>;
    
    void main()
    
    {
    
    char a = 1;
    
    char c[] = "1234567890";
    
    char *p ="1234567890";
    
    a = c[1];
    
    a = p[1];
    
    return;
    
    }
    
    

    对应的汇编代码

    
    10: a = c[1];
    
    00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
    
    0040106A 88 4D FC mov byte ptr [ebp-4],cl
    
    11: a = p[1];
    
    0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
    
    00401070 8A 42 01 mov al,byte ptr [edx+1]
    
    00401073 88 45 FC mov byte ptr [ebp-4],al
    
    

    第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。


    3.7小结: 
    堆和栈的区别可以用如下的比喻来看出: 
    使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 
    使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

    堆和栈的区别主要分: 
    操作系统方面的堆和栈,如上面说的那些,不多说了。 
    还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。 
    虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。

    展开全文
  • 局部变量,如果是基本数据类型,那么就直接存在中,如果是应用数据类型,比如String str = new String("12");,会把对象存在中,对象的引用(指针)存在中,成员变量,类的成员不同对象中各不相同...

    局部变量,如果是基本数据类型,那么就直接存在栈中,如果是应用数据类型,比如String str = new String("12");,会把对象存在堆中,对象的引用(指针)存在栈中,

    成员变量,类的成员在不同对象中各不相同,基本数据类型和引用数据类型都存储在这个对象中,作为一个整体存储在堆中。而类的方法是所有的对象共享的,方法是存在方法区的,只用当调用的时候才会被压栈,不用的时候是占内存的。

    展开全文
  • 文章目录一、存储区域介绍二、ubuntu系统中输出信息进行验证三、Keil中针对stm32系统进行验证四、总结五、参考资料 ...区(stack)–由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类

    一、存储区域介绍

    • C语言在内存中一共分为如下几个区域
    区域作用
    内存栈区存放局部变量名
    内存堆区存放new或者malloc出来的对象
    常数区存放局部变量或者全局变量的值
    静态区用于存放全局变量或者静态变量
    代码区二进制代码
    • 区域的解释

    栈区(stack)–由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

    堆区(heap)–般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式类似于链表。

    全局区(静态区)(static)–全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(ZI)。程序结束后有系统释放。 和“栈”一样,通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。

    文字常量区–常量字符串就是放在这里的。程序结束后由系统释放 (RO)

    程序代码区–存放函数体的二进制代码。 (RO)

    常量存储区—和“全局/静态存储区”一样,通常是用于那些在编译期间就能确定存储大小的常量的存储区,并且在程序运行期间,存储区内的常量是全局可见的。这是一块比较特殊的存储去,他们里面存放的是常量,不允许被修改。

    • 内存存在两种属性:静态分配内存和动态分配内存。

    静态分配内存:是在程序编译和链接时就确定好的内存。
    动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存。

    • 堆栈

    堆和栈都是动态分配内存,两者空间大小都是可变的。

    Stack: 栈,存放Automatic Variables,按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。

    通常是用于那些在编译期间就能确定存储大小的变量的存储区,用于在函数作用域内创建,在离开作用域后自动销毁的变量的存储区。通常是局部变量,函数参数等的存储区。他的存储空间是连续的,两个紧密挨着定义的局部变量,他们的存储空间也是紧挨着的。栈的大小是有限的,通常Visual C++编译器的默认栈的大小为1MB,所以不要定义int a[1000000]这样的超大数组。

    Heap: 堆,自由申请的空间,按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
    通常是用于那些在编译期间不能确定存储大小的变量的存储区,它的存储空间是不连续的,一般由malloc(或new)函数来分配内存块,并且需要用free(delete)函数释放内存。如果程序员没有释放掉,那么就会出现常说的内存泄漏问题。需要注意的是,两个紧挨着定义的指针变量,所指向的malloc出来的两块内存并不一定的是紧挨着的,所以会产生内存碎片。另外需要注意的一点是,堆的大小几乎不受限制,理论上每个程序最大可达4GB。
    每个线程都会有自己的栈,但是堆空间是共用的。

    • Text & Data & Bss

    .text: 也称为代码段(Code),用来存放程序执行代码,同时也可能会包含一些常量(如一些字符串常量等)。该段内存为静态分配,只读(某些架构可能允许修改)。 这块内存是共享的,当有多个相同进程(Process)存在时,共用同一个text段。

    .data: 也有的地方叫GVAR(global value),用来存放程序中已经初始化的非零全局变量。静态分配。 data又可分为读写(RW)区域和只读(RO)区域。
    -> RO段保存常量所以也被称为.constdata
    -> RW段则是普通非常全局变量,静态变量就在其中 .bss: 存放程序中为初始化的和零值全局变量。静态分配,在程序开始时通常会被清零。

    • 从低地址到高地址
      在这里插入图片描述

    二、在ubuntu系统中输出信息进行验证

    • 输入代码main.c
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
    void before()
    {
     
    }
     
    char g_buf[16];
    char g_buf2[16];
    char g_buf3[16];
    char g_buf4[16];
    char g_i_buf[]="123";
    char g_i_buf2[]="123";
    char g_i_buf3[]="123";
     
    void after()
    {
     
    }
     
    int main(int argc, char **argv)
    {
            char l_buf[16];
            char l_buf2[16];
            char l_buf3[16];
            static char s_buf[16];
            static char s_buf2[16];
            static char s_buf3[16];
            char *p_buf;
            char *p_buf2;
            char *p_buf3;
     
            p_buf = (char *)malloc(sizeof(char) * 16);
            p_buf2 = (char *)malloc(sizeof(char) * 16);
            p_buf3 = (char *)malloc(sizeof(char) * 16);
     
            printf("g_buf: 0x%x\n", g_buf);
            printf("g_buf2: 0x%x\n", g_buf2);
            printf("g_buf3: 0x%x\n", g_buf3);
            printf("g_buf4: 0x%x\n", g_buf4);
     
            printf("g_i_buf: 0x%x\n", g_i_buf);
            printf("g_i_buf2: 0x%x\n", g_i_buf2);
            printf("g_i_buf3: 0x%x\n", g_i_buf3);
     
            printf("l_buf: 0x%x\n", l_buf);
            printf("l_buf2: 0x%x\n", l_buf2);
            printf("l_buf3: 0x%x\n", l_buf3);
     
            printf("s_buf: 0x%x\n", s_buf);
            printf("s_buf2: 0x%x\n", s_buf2);
            printf("s_buf3: 0x%x\n", s_buf3);
     
            printf("p_buf: 0x%x\n", p_buf);
            printf("p_buf2: 0x%x\n", p_buf2);
            printf("p_buf3: 0x%x\n", p_buf3);
     
            printf("before: 0x%x\n", before);
            printf("after: 0x%x\n", after);
            printf("main: 0x%x\n", main);
     
            if (argc > 1)
            {
                    strcpy(l_buf, argv[1]);
            }
            return 0;
    }
    

    l_buf/l_buf2/l_buf3 ,直接定义,是由编译器自动分配的,存储在栈中
    s_buf/s_buf2/s_buf3,定义static,编译器编译时分配内存。为全局变量,在全局初始化区
    p_buf/p_buf2/p_buf3,他们指向的空间,通过malloc申请空间,存放在堆中
    g_buf/g_buf2/g_buf3/g_buf4/,定义的为全局变量,在全局初始化区

    • 运行结果
      在这里插入图片描述
    • 分析结果
      栈存放区域是由高地址到低地址向下增长
      堆存放区是由低地址到高地址像上增长
      静态变量地址从高地址到低地址向下增长
      函数地址是从低地址到高地址向上增长

    三、在Keil中针对stm32系统进行验证

    • 总结
    内存高地址栈区
    堆区
    .bss段
    .data段
    常量区
    内存低地址代码区
    • 在MDK中编译后可以看到Code、RO-data、RW-data、ZI-data的大小

    Code是存储程序代码的;
    RO-data是存储const常量和指令
    RW-data是存储初始化值不为0的全局变量
    ZI-data是存储未初始化的全局变量或初始化值为0的全局变量

    在这里插入图片描述

    • keil中的代码
    #include "delay.h"
    #include "usart.h"
    #include "string.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    int k1 = 1;
    int k2;
    static int k3 = 2;
    static int k4;
    int main(void)
     {
    	delay_init();	    	 //延时函数初始化	
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
    	uart_init(115200);	 //串口初始化为115200
    	 
    	 while(1)
    	{
        static int m1=2, m2;
        int i = 1;
        char *p;
        char str[10] = "hello";
        char *var1 = "123456";
        char *var2 = "abcdef";
        int *p1=malloc(4);
        int *p2=malloc(4);
        free(p1);
        free(p2);
        printf("栈区-变量地址");
    	printf("   i:%p\r\n", &i);
    	printf("                p:%p\r\n", &p);
    	printf("              str:%p\r\n", str);
        printf("堆区-动态申请地址");
        printf("  %p\r\n", p1);
        printf("                   %p\r\n", p2);
        printf("\r\n.bss段\r\n");
    	printf("全局外部无初值 k2:%p\r\n", &k2);
    	printf("静态外部无初值 k4:%p\r\n", &k4);
    	printf("静态内部无初值 m2:%p\r\n", &m2);
        printf("\r\n.data段\r\n");
        printf("全局外部有初值 k1:%p\r\n", &k1);
        printf("静态外部有初值 k3:%p\r\n", &k3);
        printf("静态内部有初值 m1:%p\r\n", &m1);
        printf("\r\n常量区\r\n");
        printf("文字常量地址     :%p\r\n",var1);
        printf("文字常量地址     :%p\r\n",var2);
        printf("\r\n代码区\r\n");
        printf("程序区地址       :%p\r\n",&main);
    	}
    }
    
    • 串口调试结果
      在这里插入图片描述
    • 分析结果可知,stm32的栈区的地址值是从上到下减小的,堆区则是从上到下增长的。

    四、总结

    通过这次学习让我对C程序的内存分配有进一步的认识,知道一个C程序内存包括的部分,了解了栈和堆地址变化的不同。而且在不同系统中,区域内的地址值变化不一定是相同的。

    五、参考资料

    1、https://blog.csdn.net/feier7501/article/details/8564300
    2、https://blog.csdn.net/jirryzhang/article/details/79518408
    3、https://blog.csdn.net/qq_43279579/article/details/110308101

    展开全文
  • stm32下了解全局变量、局部变量对分区的了解各区特点stm32下实现对分区的了解 对分区的了解 一个STM32程序代码中,从内存高地址到内存低地址,依次分布着区、区、全局区(静态区)、常量区、代码区,...
  • 成员变量在堆内存里,局部变量在栈内存里。(基础类型) 我有疑惑: 既然成员变量存在于对象中,对象存在于中,所以成员变量存在于中。那么按照这样的推理,局部变量存在于方法中,而方法存在于对象中,对象存在...
  • Java中的变量类型根据不同的标准可以分为两类,如果以其引用的数据类型的不同来区分可分为“原始数据类型变量和引用数据类型变量”,如果以其作用范围的不同来区分可分为“局部变量,实例变量和静态变量”。...
  • 全局变量和局部变量在内存里的区别? 转:一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等...
  • 单片机全局变量 局部变量

    千次阅读 2017-01-06 12:50:11
    局部变量,全局变量
  • 成员变量在堆内存里,局部变量在栈内存里。(基础类型) 我有疑惑: 既然成员变量存在于对象中,对象存在于中,所以成员变量存在于中。那么按照这样的推理,局部变量存在于方法中,而方法存在于对象中,对象存在...
  • 先看这两个代码: 这两段代码只是调用的...fmt.println函数使局部变量的作用域超出了函数的作用域,所以局部变量在堆上。而println是内联函数,并没有使局部变量的作用域逃出函数的作用域,所以是在栈上。 ...
  •  C++中,局部函数里面,new一个内存块,地址是在堆中,而其他的变量基本在栈中。中的变量内存随着局部函数的结束而被自动销毁,的则不会,需要自己delete销毁。  举个常见的错误: int* Func1() { int p...
  • 全局变量和局部变量在内存中的区别 C语言经过编译之后将内存分为以下几个区域: (1)(stack):由编译器进行管理,自动分配和释放,存放函数调用过程中的各种参数、局部变量、返回值以及函数返回地址。操作...
  • 概念 常量池 常量池的好处 ...对于这个问题,可能很多人都可以脱口而出 : 用final修饰的变量是常量 ,或者是编译时期定义好的字符串。(字符串常量) 但是这种说法是不严谨的,因为准确来说 : 常量是...
  • 全局变量,静态局部变量局部变量空间的分配和分配 其中全局变量和静态局部变量时从 静态存储区中划分的空间, 二者的区别在于作用域的不同,全局变量作用域大于静态局部...
  • 桢会储存该方法内用到的局部变量表,操作,动态链接,方法出入口等信息 【一个方法的调用到该方法调用结束,,就是一个Java中入栈到出栈的全过程】 4. 本地方法 与Java类似,但他是为本地...
  • 全局、静态、new产生的变量都在堆中,动态分配的变量在堆中分配,局部变量在栈里面分配。函数中声明的变量在栈中,用了new标识符在堆中,全局变量和static变量全局区。程序为变量分配动态内存,程序结束为...
  • c++的成员变量在堆还是栈

    千次阅读 2018-05-11 15:51:33
    即:如果对象是函数内的非静态局部变量,则对象,对象的成员变量保存在栈区。如果对象是全局变量,则对象,对象的成员变量保存静态区。如果对象是函数内的静态局部变量,则对象,对象的成员变量保存静态区。如果...
  • 成员变量和局部变量

    千次阅读 2018-04-07 22:17:43
    成员变量和局部变量1,两者的作用域不同:局部变量只能定义它的方法中被使用,出了方法就等于被销毁;(全局)成员变量是创建类中但又方法之外的变量,它的作用范围是整个类2,初始值不同:假如我们不给变量...
  • 全集变量、局部变量、静态全局变量、静态局部变量在内存中如何存储,有什么区别,的区别,这都是C/C++的基础问题。各种招聘笔试面试中,经常都能够遇到与之相关的问题。前些日子我看了一些与之相关的文章,...
  • 2.以其作用范围的不同来区分可分为“局部变量,实例变量和静态变量” (其中实例变量和静态变量static 统称为成员变量) 局部变量和成员变量的区别: 成员变量: 1、成员变量定义类中,整个类中都可以被...
  • JVM虚拟机局部变量表与操作数) 虚拟机概述 由于跨平台性的设计,Java的指令都是根据来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。 优点时跨平台,指令集小,编译器容易实现,缺点时...
  • go语言局部变量分配在栈还是堆?

    千次阅读 2018-08-26 13:50:42
    看来确实是go语言会根据局部变量有没有发生逃逸行为来自动决定一个局部变量是分配在栈还是分配在堆。 对于动态new出来的局部变量,go语言编译器也会根据是否有逃逸行为来决定是分配在堆还是栈,而不是直接分配...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 166,321
精华内容 66,528
关键字:

局部变量在堆还是栈