IAR栈堆设置大小—》右键点击Option—》点击Linker—》点击Config—点击Edit
注意:KEIL的栈堆修改可以直接在启动文件修改,百度一下就有。
内存知识
C进程内存布局
任何的程序在运行起来变成一个进程的时候 ,他都需要有内存的资源来给他存放进程中的变量\常量\函数\代码…等.这些不同的数据内同他们所存放的内存区也是不一样,而且不同的内存区有不同的特性,我们所研究的内存布局则是研究不同的内存有什么不同的特性。
每一C语言程序当他运行起来的时候都会获得一块完全一摸一样的虚拟内存,虚拟内是由物理内存映射而来的一个寻址范围,方便开发者独立开发自己的程序,不需要考虑到实际的物理内存的分配问题。
VM: Virtual Memory (虚拟内存)
PM: Physical Memory (物理内存)
虚拟内存中分为一下几个区域:
栈 ( stack )
堆 ( heap)
数据段
代码段
char * msg = "Hello"; // 指针指向只读的内存区
char buf[] = "Hello"; // buf 数组在初始化的时候把常量区的内容"Hello" 拷贝到栈空间
栈内存
什么东西被存放与栈空间:
1、环境变量
2、命令行参数
3、局部变量 (形参也是局部变量)
栈内存区有什么特性:
**栈空间非常有限.尤其在嵌入式的环境中.因此在做嵌入式开发过程中应该尽量少使用栈空间.*。
$ ulimit -a
stack size (kbytes, -s) 8192 --> 8M
在程序内部每调用一个新的函数,栈空间就会减少一段,用来存放该函数的局部变量,当每一函数退出的时候,栈空间会向上回缩一段,该函数将会把他所占用的栈空间交还给系统,栈空间的申请与释放没办法手动干预,所有的操作都由系统来实现。
临时修改栈空间的大小
$ ulimit -s 10240 // 临时修改为10M
数据段
静态数据:
1、全局变量, 指的是在函数体外面定义的变量,称为全局变量
2、被static修饰的局部变量.(注意:解释如下)
//全局变量 静态变量
int a ; // 全局变量 数据段的.bss段 未初始化的静态数据
int b = 100 ; // 全局变量 , 数据段的.data段中 , 已初始化的静态数据
int main(int argc, char const *argv[])
{
int num = 100 ; // 局部变量 ,存放与栈空间
static int num1 = 200 ; // 被static修饰的局部变量--> 静态变量 存放与数据段 .data
static int num2 ; // 被static修饰的局部变量--> 静态变量 存放与数据段 .bss
return 0;
}
为什么会有静态数据:
全局变量,在默认情况下是跨文件可见,可以作为多个文件或者多个函数之间共享数据的一个简单途径。
static 修饰的静态数据,该语句只会被执行一次,而且他的值将会被一直保留方,便下一次用该值,直到程序退出。
void func(void)
{
static int num = 0 ; //存放于数据段 ,当函数退出的时候并不会影响该变量的存储
int num1 = 0 ; // 存放与栈空间, 但函数退出的时候其内存一并被释放
printf("num:%d \n", num );
printf("num1:%d \n", num1 );
num1 ++ ;
num ++ ;
return ;
}
数据段的分区
.bss 未初始化的静态数据 , 内容将会自动被清空为0
.data 已初始化的静态数据
.rodata 常量 100\200\ “Hello”
代码段
.text 段: 用于存放用户的代码
.init 段: 用于存放系统的初始化代码(程序运行需要提前做的准备)
堆内存
堆内存(heap) , 又称为动态内存、自由内存,简称堆。堆是唯一一个开发给开发中自行管理的内存区,何时申请,何时释放,申请内存区的大小等等都是由开发者自行决定。系统不会去干预管理所有的细节都是由开发者自行把握,给予开发者绝对的自由,对如何管理内存有很高的要求,应该做到申请了就记得释放, 不然会造成内存泄漏。
堆内存的特征:
相对于栈内存,对内存的大小相当大, 对空间的大小取决于物理内存的大小。
栈内存是从上往下增长, 而堆内存则相反从下往上增长。
堆内存是匿名的,只能通过指针来访问。
自行定义以及分配堆空间, 释放与申请都是由开发者自行解决。除非程序退出
相关API接口:
申请内存: malloc / calloc / realloc (注意:用的多是malloc和calloc)
释放内存: free
清空: bzero / memset
malloc ( 配置内存空间 )
头文件:
#include <stdlib.h>
定义函数:
void *malloc(size_t size);
参数分析:
size --> 需要申请的内存的大小
返回值:
成功返回一个指针指向该空间
失败 返回NULL
// 先申请一片 堆空间 大小为 4 , 并返回的地址赋值给p
int * p = malloc(sizeof(int));
*p = 100 ; // 把100 放到p所指向的堆空间中
printf("*p:%d p:%p &p:%p\n", *p , p , &p );
free(p) ; // 释放申请堆空间
printf("*p:%d p:%p &p:%p\n", *p , p , &p ); // 访问非法内存, 因为刚才已经释放了该内存 , 不应该在访问他
p = NULL ; // 释放之后应该然指针指向空, 也不应该继续访问他,否则成为野指针。
free ( 释放原先配置的内存)
头文件:
#include <stdlib.h>
定义函数:
void free(void *ptr);
参数分析:
ptr --> 需要释放的内存的起始地址
返回值:
无返回值
calloc ( 配置内存空间 )
头文件:
#include <stdlib.h>
定义函数:
void *calloc(size_t nmemb, size_t size);
参数分析:
nmemb --> 需要多少个连续的内存空间(多少个房间)
size --> 每一个内存空间的大小(每个房间多大)
返回值:
成功返回一个指针指向该内存(堆)
失败返回NULL
清楚内存
清空内存
bzero ( 将一段内存内容全清为零 )
头文件:
#include <string.h>
定义函数:
void bzero(void *s, int n);
参数分析:
s --> 指向需要清空的内存的入口地址
n --> 需要清空的N字节
返回值:
无
memset ( 将一段内存空间填入某值 )
头文件:
#include <string.h>
定义函数:
void * memset(void *s, int c, size_t n);
参数分析:
s --> 需要设置的内存空间的入口地址
c --> 需要填入内内存的值
n --> 需要清空的内存区的大小
返回值:
返回指针s
注意:
memset(p , 'A' , sizeof(int)*10 );
以上代码是把字符'A'按一个一个字节填入指针p所指向的内存中 , 一共填入了40个
memset在填入内存的时候是按一个一个字节进行填入
重新分配内存地址:
头文件:
#include <stdlib.h>
函数原型:
void *realloc(void *ptr, size_t size);
参数分析:
ptr --> 原有的内存入口地址
size --> 现在需要的大小
返回值:
成功返回新的内存地址入口
失败返回NULL
注意:
该函数主要是用来实现内存的重新分配,在重新分配的过程中会尽可能保持数据内容不变,如果是原本内存扩大,则会把原有数据完成搬迁,如果是缩小,则保证在容量允许的情况下的数据不变。
释放内存 的含义:
释放内存意味着内存 的使用权将移交给系统。
释放内存并不会改变指针的指向。
释放内存并不意味着内存的数据会被清除