1.内存使用情况
我们一般会使用free命令来查看系统的内存使用情况,如下
root@zihome:# free
total used free shared buffers
Mem: 125848 57332 68516 0 3160
-/+ buffers: 54172 71676
Swap: 62460 0 62460
我们再使用/proc/meminfo来看下,应该会更加直观
root@zihome:/# cat /proc/meminfo
MemTotal: 125848 kB
MemFree: 68436 kB
Buffers: 3160 kB
Cached: 15100 kB
SwapCached: 0 kB
Active: 14932 kB
Inactive: 11948 kB
Active(anon): 8724 kB
Inactive(anon): 76 kB
Active(file): 6208 kB
Inactive(file): 11872 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 62460 kB
SwapFree: 62460 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 8656 kB
Mapped: 9908 kB
Shmem: 180 kB
Slab: 12484 kB
SReclaimable: 1804 kB
SUnreclaim: 10680 kB
KernelStack: 1008 kB
PageTables: 536 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 125384 kB
Committed_AS: 96256 kB
VmallocTotal: 1048372 kB
VmallocUsed: 12076 kB
VmallocChunk: 1025184 kB
Linux在内存的使用上的宗旨是:如果内存充足,不用白不用,尽量用内存来缓存一些文件,从而加快进程的运行速度,而当内存不足时,这些内存又会被回收,供程序使用。
所以真正可用的内存是:MemFree + Buffers + Cached = 68436 + 3160 +15100 = 86696
2.虚拟内存和物理内存
我们在上面用命令查到的是物理内存的使用情况,实际在写代码的时候我们面对的是虚拟内存,在32为操作系统上,每个进程有4GB的内存空间,不过真正使用的是3G用户空间,有1G是内核空间,是和所有程序共享。
一张典型的C语言在linux系统下的占区图:
可以看出,对于Linux系统下的,存储空间的分配有着较为层次清晰的分层。单片机大概也遵循这个分区架构。
- 二进制代码以及常量(CONST修饰)以及全局变量在最底层,存储空间最靠前的部分
- 然后是堆区,堆区向上增长,我们常用到的molloc()、free()等函数操作的就是这个区,这也是芯片系统中唯一可以让程序员通过代码操作的一片存储空间
- 再然后是动态链接库
- 在往上(高地址)便是栈区,由编译器自动分配和释放,存放函数的参数值、局部变量的值等。
- 最高地址一般为操作系统内核,用户无法访问
一个正常的程序在内存中通常分为程序段、数据端、堆栈三部分
- 程序代码区,存放函数体的二进制代码。
- 文字常量区,常量字符串就是放在这里的,程序结束后由系统释放
- 全局区(静态区)(static),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量、未初始化的静态变量在相邻的另一块区域,程序结束后有系统释放
- 堆区(heap)一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
- 栈区(stack),由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
如下例子:
int a=0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[]="abc"; //栈
char *p3= "1234567"; //在文字常量区Flash
static int c =0 ; //静态初始化区
p1= (char *)malloc(10); //堆区
strcpy(p1,"123456"); //"123456"放在常量区
}
- 在调用malloc的时候其实实在堆区(虚拟内存)申请了空间
- 知道使用strcpy的时候才真正使用内存,所以这时候才分配了物理内存使用。
在每个进程的maps里面可以看到每个区多处于的地址范围。
root@zihome:/proc/1821# cat maps
00400000-0042a000 r-xp 00000000 1f:05 660 /usr/sbin/dropbear
0043a000-0043b000 rw-p 0002a000 1f:05 660 /usr/sbin/dropbear
00581000-00584000 rw-p 00000000 00:00 0 [heap]
00584000-0059b000 rw-p 00000000 00:00 0 [heap]
77ed8000-77f2f000 r-xp 00000000 1f:05 786 /lib/libuClibc-0.9.33.2.so
77f2f000-77f3e000 ---p 00000000 00:00 0
77f3e000-77f3f000 r--p 00056000 1f:05 786 /lib/libuClibc-0.9.33.2.so
77f3f000-77f40000 rw-p 00057000 1f:05 786 /lib/libuClibc-0.9.33.2.so
77f40000-77f45000 rw-p 00000000 00:00 0
77f45000-77f5b000 r-xp 00000000 1f:05 766 /lib/libgcc_s.so.1
77f5b000-77f6a000 ---p 00000000 00:00 0
77f6a000-77f6b000 rw-p 00015000 1f:05 766 /lib/libgcc_s.so.1
77f6b000-77f6e000 r-xp 00000000 1f:05 775 /lib/libcrypt-0.9.33.2.so
77f6e000-77f7d000 ---p 00000000 00:00 0
77f7d000-77f7e000 rw-p 00002000 1f:05 775 /lib/libcrypt-0.9.33.2.so
77f7e000-77f8f000 rw-p 00000000 00:00 0
77f8f000-77f90000 r-xp 00000000 1f:05 765 /lib/libutil-0.9.33.2.so
77f90000-77f9f000 ---p 00000000 00:00 0
77f9f000-77fa0000 rw-p 00000000 1f:05 765 /lib/libutil-0.9.33.2.so
77fa0000-77fa7000 r-xp 00000000 1f:05 798 /lib/ld-uClibc-0.9.33.2.so
77fb4000-77fb6000 rw-p 00000000 00:00 0
77fb6000-77fb7000 r--p 00006000 1f:05 798 /lib/ld-uClibc-0.9.33.2.so
77fb7000-77fb8000 rw-p 00007000 1f:05 798 /lib/ld-uClibc-0.9.33.2.so
7ff69000-7ff8a000 rwxp 00000000 00:00 0 [stack]
7fff7000-7fff8000 r-xp 00000000 00:00 0 [vdso]
内存的分配最小单位是4KB,反正内存的申请和释放都是根据代码申请多少就是多少,这样频繁的申请释放肯定消耗性能,所以只malloc一点点,也会申请4+128KB
在申请小内存的时候使用malloc,系统调用brk来调整堆顶的地址(超过原本的限制,就会往上一直调整),当申请大内存的时候,会使用mmap申请,这时候就会直接开辟一个新的堆地址空间。
而栈的扩展就是通过压栈的方式,因为栈是在最上面的地方,所以就往下一直调整
优化数据段的方法
1.尽可能减少全局变量和静态变量
2.对于非内置类型的全局变量(类,结构体),尽可能使用全局对象指针来代替
3.将只读的全局变量,加上const,从而使其转移到代码段,利用代码段是系统共享的特性达到节省内存是哟个的目的
4.不要在头文件中定义变量
动态库
动态库在程序编译的时候不会被链接到目标代码中,而是在程序运行时才被载入,因此在程序运行时还需要动态库的存在(除了拷贝可执行文件,还要拷贝到/usr/lib/里面去)。
动态库有数据段和代码段组成(堆\栈属于调用这个动态库的进程所有)
代码段的共享性,所以一个动态库被多个进程调用,就会有多个数据段,但是只有一个代码段。
1.去掉无用的动态库readelf查看依赖的动态库
2.动态库的合并
3.仅被依赖一次的动态库
静态库
静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要加载静态库。
linux C语言 内存申请 堆 栈 大小限制:https://blog.csdn.net/xxxxxx91116/article/details/10068555
Linux内存分配机制:https://www.cnblogs.com/wangliangblog/p/9109384.html