探究操作系统的内存分配(malloc)对齐策略
问题:
我们在写程序的时候经常发现程序使用的内存往往比我们申请的多,为了优化程序的内存占用,搅尽脑汁想要优化内存占用,可是发现自己的代码也无从优化了,怎么办?现在我们把我们的焦点放到malloc上,毕竟我们向系统申请的内存都是通过它完成了,不了解他,也就不能彻底的优化内存占用。
来个小例子

//g++ -o malloc_addr_vec mallc_addr_vec.cpp 编译
2 #include<iostream>
3 using namespace std;
4 int main(int argc, char *argv[])
5 {
6 int malloc_size = atoi(argv[1]);
7 char * malloc_char;
8 for (size_t i = 0; i < 1024*1024; ++i) {
9 malloc_char = new char[malloc_size];
10 }
11 while (1) {}//此时查看内存占用
12 return 0;
13 }

本文的测试环境为Linux 64Bit ,使用G++编译为可执行文件后,使用不同的启动参数启动,使用top命令查看程序占用的内存,这里我们主要是看RES指标
RES -- Resident size (kb)
The non-swapped physical memory a task has used.
测试案例:
1.每次new 1 Byte Do 1024*1024次
./malloc_addr_vec 1
启动程序后的内存占用
内存消耗 32MB
2.每次new 24 Byte Do 1024*1024次
./malloc_addr_vec 24
启动程序后的内存占用
内存消耗32MB
3.每次new 25 Byte Do 1024*1024次
./malloc_addr_vec 25
启动程序后的内存占用
内存消耗48MB
为什么我们每次new 1Byte 和每次 new 24Byte系统消耗的内存一样呢?,为什么每次new 25Byte和 每次new 24Byte占用的内存完全不同呢?
不知道大家在写程序的时候有没有关注过这个问题。我一次遇到时,吐槽一句:What the fuck malloc.
原因分析:
在大多数情况下,编译器和C库透明地帮你处理对齐问题。POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于任何的C类型来说都是对齐的。
对齐参数(MALLOC_ALIGNMENT) 大小的设定并需满足两个特性
1.必须是2的幂
2.必须是(void *)的整数倍
至于为什么会要求是(void *)的整数倍,这个目前我还不太清楚,等你来发现...
根据这个原理,在32位和64位的对齐单位分别为8字节和16字节
但是这并解释不了上面的测试结果,这是因为系统malloc分配的最小单位(MINSIZE)并不是对齐单位
为了进一步了解细节,从GNU网站中把glibc源码下载下来,查看其 malloc.c文件

其中request2size这个宏就是glibc的内存对齐操作,MINSIZE就是使用malloc时占用内存的最小单位。根据宏定义可推算在32位系统中MINSIZE为16字节,在64位系统中MINSIZE一般为32字节。从request2size还可以知道,如果是64位系统,申请内存为1~24字节时,系统内存消耗32字节,当申请内存为25字节时,系统内存消耗48字节。 如果是32位系统,申请内存为1~12字节时,系统内存消耗16字节,当申请内存为13字节时,系统内存消耗24字节。
一般他们的差距是一个指针大小,计算公式是
max(MINSIZE,in_use_size)
其中in_use_size=(要求大小+2*指针大小-指针大小)align to MALLOC_ALIGNMENT
(对于上面计算的由来可以参见glibc 内存池管理 ptmalloc这篇文章的第4节chuck部分以及搜一下malloc的内部实现源码 )
为了证明这个理论的正确性,我们需要计算一次malloc到底花掉了多少内存,我们用如下代码分别在32bit Linux和 64bit Linux上做测试

2 #include<stdio.h>
3 #include<stdlib.h>
4 int main()
5 {
6 char * p1;
7 char * p2;
8 int i=1;
9 printf("%d\n",sizeof(char *));
10 for(;i<100;i++)
11 {
12 p1=NULL;
13 p2=NULL;
14 p1=(char *)malloc(i*sizeof(char));
15 p2=(char *)malloc(1*sizeof(char));
16 printf("i=%d %d\n",i,(p2-p1));
17 }
18
19 getchar();
20 }

其测试结果如下:
32bit

64bit
了解了malloc的内存对其原理后,对于程序的内存占用的优化又有了有的放矢。我们可以根据内存对齐的原则来请求内存,来制作我们的高效内存池,从而避免隐形的资源浪费.
例如,目前STL的内存池是以8Byte为对齐单位,内存池free_list大小为
free_list[0] --------> 8 byte
free_list[1] --------> 16 byte
free_list[2] --------> 24 byte
free_list[3] --------> 32 byte
... ...
free_list[15] -------> 128 byte
STL内存池在发现某个规则的内存用完了时,会进行refill,在进行chunk_alloc
例如8Byte大小的空间没有了,调用refill,refill会将其空间准备20个,也就是20*8,当然refill做不了内存分配,他把20个8Byte的需求提交给chunk_alloc
chunk_alloc 能真正分配内存,但是它分配的时候会将内存空间*2,所以最终malloc的内存为8*20*2=320 ,32bit系统给malloc的内存为328,64bit系统给malloc的内存为336
探究操作系统的内存分配(malloc)对齐策略的更多相关文章
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- 【007】【JVM——内存分配和恢复策略】
内存分配与收回策略 JVM的自己主动内存管理要自己主动化地解决两个问题:对象分配内存以及回收分配给对象的内存.回收内存前几篇已经讲了.如今说内存分配.对象的内存分配一般分配在堆内存中,也可能经过 ...
- Java虚拟机内存分配与回收策略
内存分配与回收策略 Minor GC 和 Full GC Minor GC:发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行, 执行的速度一般也会比较快. Full GC ...
- JVM垃圾回收器、内存分配与回收策略
新生代垃圾收集器 1. Serial收集器 serial收集器即串行收集器,是一个单线程收集器. 串行收集器在进行垃圾回收时只使用一个CPU或一条收集线程去完成垃圾回收工作,并且会暂停其他的工作线程( ...
- JVM学习十 -(复习)内存分配与回收策略
内存分配与回收策略 对象的内存分配,就是在堆上分配(也可能经过 JIT 编译后被拆散为标量类型并间接在栈上分配),对象主要分配在新生代的 Eden 区上,少数情况下可能直接分配在老年代,分配规则不固定 ...
- [转]内存分配malloc, new , heapalloc
malloc,new,VirtualAlloc,HeapAlloc性能(速度)比较 http://www.cppblog.com/woaidongmao/archive/2011/08/12/1531 ...
- JVM的内存分配和回收策略
对象的Class加载 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应 ...
- 转: Linux C 动态内存分配 malloc及相关内容 .
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
- 浅谈java内存分配和回收策略
一.导论 java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配.通俗的讲,对象的内存分配 ...
随机推荐
- HDU 5072 Coprime (单色三角形+容斥原理)
题目链接:Coprime pid=5072"> 题面: Coprime Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...
- 云平台DevOps实践
基于TFS的.net技术路线的云平台DevOps实践 DevOps是近几年非常流行的系统研发管理模式,很多公司都或多或少在践行DevOps.那么,今天就说说特来电云平台在DevOps方面的实践吧. ...
- 【u219】最长链
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 现给出一棵N个结点二叉树,问这棵二叉树中最长链的长度为多少,保证了1号结点为二叉树的根. [提示] 关 ...
- 【t064】最勇敢的机器人
Time Limit: 1 second Memory Limit: 128 MB [问题描述] [背景] Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了~ [问题描述] ...
- _Decoder_Interface_init xxxxxx in amrFileCodec.o
Undefined symbols for architecture arm64: "_Decoder_Interface_init", referenced from: Deco ...
- Android Studio打包apk,aar,jar包
转载请标明出处:一片枫叶的专栏 文本我们将讲解android studio打包apk,aar,jar包的相关知识.apk包就是android系统的安装包,这里没什么好说的,aar包是android中独 ...
- git merge与rebase
参考这篇文章 Git 之 merge 与 rebase 的区别 文章2 另外,使 rebase出现冲突后,先修改冲突,然后git add 某文件(我使用add .经常有问题),然后git reba ...
- 哪个项目管理工具好用到哭?JIRA VS 华为软件开发云
一.产品介绍 JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪.客户服务.需求收集.流程审批.任务跟踪.项目跟踪和敏捷管理等工作领域. 华为软件开发云 (DevCloud ...
- c语言学习笔记(4)——流程控制
一.什么是流程控制 程序代码执行的顺序 流程控制分类 顺序执行 选择执行 定义 有选择的执行某些代码 分类 if switch 循环执行 定义 某些代码会被重复执行 分类 for while do w ...
- Android中WebView的相关使用
近期做的项目中,遇到个非常棘手的问题: 客户给我的数据是有限制的,因此,在返回某条详细页面内容的时候,他仅仅能给我一个html片段,里面包括 文字,图片以及附件的下载地址.假设网页模版规范的爱比較好说 ...


