malloc函数的底层实现你是否清楚
malloc函数的底层实现你是否清楚
说起malloc函数,每个人都能说出它的功能,而且我们经常会用到,那么今天我要说的是关于malloc函数在编译器的底层实现,如果你对它的实现已经很清楚了,那么你可以不往下看了,因为这篇博客只是就它的一些简单原理进行了整理,你可以等我的下一篇博客,对它的深层的一些函数在进行的一些讲述。
这篇博客对于深层的函数实现并没有解释,只是让我们明白了windows系统中的一些分配算法的原理。请读者多多指正,因为在空闲链表分配算法上我看到过不同的说法。
关于VirtualAlloc函数:
首先我们来看一下VirtualAlloc函数,它是WINDOWS系统提供给我们的一个API,它的功能就是向操作系统给我们批发内存。为什么叫批发呢,因为在操作系统中并不是我们所编写的应用程序直接向系统申请内存,在VirtualAlloc函数向内存申请内存的时候是申请内存的大小必须是4096字节的整数倍,这就相当于是一个水果贩子去大批发市场进货,人家批发市场是有起发的要求的,不是说你去买上几斤都行,所以我们都是从水果贩子的手上再去买水果。这样是有道理的,因为你一个程序假如只需要申请几字节的内存,那么系统给我们4096字节的大小是不是很浪费。
那么用VirtualAlloc申请的内存又是怎么拿给我们的程序来用的呢,在这里就牵扯到了分配算法。其实在windows中在对管理器上提供了几个函数用来创建、分配、释放和销毁堆空间(我们申请的空间是在堆上的),从而实现了分配算法。
HeapCreat:创建一个堆
HeapAlloc:在堆里分配空间
HeapFree:释放分配的内存
HeapDestroy:销毁一个堆
这里的HeapCreat便是创建一个堆空间它申请内存空间便是通过VirtualAlloc函数来实现的。HeapAlloc函数是在堆空间里面给用户分配小的内存空间,如果内存不足它也能通过VirtualAlloc向系统申请更多的内存。
Malloc函数:
说了前面那么多,终于说道我们的重点了,malloc函数其实是上面几个Heap操作函数的包装。
堆空间是程序申请出来的一大块空间,当我们用malloc函数申请空间的时候大小是不确定的,有可能是很小的一块空间也有可能是很大的一块空间,所以对堆空间也是需要一定的方法进行管理的,当你需要申请空间的时候按照你申请的大小以一定方法分配给你。
这就是分配算法,分配算法有很多种,对于不同的场合是有不同的分配算法的。在这里只简单的描述一下几种简单的算法。
1. 空闲链表
我们知道在一块堆空间中,能用的空间到时候是一块一块的分布着,空闲链表的方法就是把这些空闲的块用链表的方式进行连接,如果用户申请一块空间,就可以遍历这个空闲链表找到能够容纳你申请的大小的一个空闲块,然后拆分,把合适大小的一块返回给你;当用户释放一块空间时,在把这块空间链接在空闲链表上。下面来看一下它的结构:
这里画的是其中的一块,在这块空间的前面存放了两个指针,N代表next指针用来指向它的下一块空间,如果下一块为空,则指针指向NULL,P代表Prev指针,用来指向它的前一块空间,如果为NULL代表他就是空闲链表的第一块空间。
这里给出了一个只有三个块的空闲链表,它们的指针指向就是如图所指那样,此时我的块都是空闲的。假如我现在要申请一块空间,它是怎么实现的呢?
假设我要申请的空间大小刚好是第二块空间的大小,那么会把第二块空间的地址返回给我们,然后把这块空间从原来的空闲链表上删掉。此时链表如下图所示:
其实一般找到的空间都是比我们所申请的空间大的,然后把这块空间进行了拆分,一部分就是就是我们所申请的空间,另一部分为剩下的空间,它还是对应在原来的空心链表上。
这样就实现了一种简单的分配算法,其实在释放这块空间的时候,虽然知道指向这块空间的指针,但是堆并不知道这块空间的大小,那么它就不知道该释放多大的一块空间。所以其实在我们刚才说的分配算法里,在给用户分配空间的时候会多分配4个字节,作用就是用来存放这块空间的大小,这样的话在释放的时候找到这一块空间,就知道这块空间到底有多大,然后进行释放。
但是,我们知道有内存越界这种情况,就是在我们用内存的时候不小心用了它后面不属于它的空间,那么像空闲链表这种结构,可能就会把那块地方存放的两个指针进行了修改,这样不就破坏了我们的链表,然后整个空间就不能再使用了,这就是这种结构的缺点。
2. 位图
还有一种分配方式是位图,它是把我们的一块堆空间进行划分,划分成大小形同的一些块,当用户申请空间时,它会给我们分配整数个块以至于能存放你所申请的大小,第一个块是头,接下来的块都是用户申请的空间的主体,这样的话在位图中,我们的每一个快都有可能且只有可能有三种情况,就是头(Head)/主体(Body)/空闲(Free)。
下图就是一个例子,在下图中分配了两片内存,第一片占用了四个块,第二片占用的五个块。
这样做的话到底有什么好处呢,首先这样分配的话,对于这个堆的存储信息,它是记录在一个数组里。因为每一个小块是有三种可能状态,那么用二进制的两个位就能够表示了,假如设为00位空闲,10位主体,11为头。这样整个位图在一个数组中就能表示了。
这样每一个堆空间都可以用N个字节来表示,比如堆的大小为1Mb,分成1M/128=8000个块(每个块设为128字节),我们知道一个int是4个字节32位,那么能用8000/(32/2)=512个int来存储,所以一个大小为512int的数组就是一个完整的位图。
位图有它的优点:
比空闲链表更加稳定,因为可以对数组进行备份,而且就算某个块损坏,也不会影响整个位图其他的块空间。
速度比较快还容易管理。
同时也有它的缺点:
也容易造成块的浪费,因为毕竟它是整数倍的分配。
当堆比较大的时候,可能这个位图会很大,数组很庞大,可能效率也并不像想象那么快。
3. 对象池
还有一种方法是对象池,也是把堆空间分成了大小相等的一些块,它是认为某些场合每次分配的空间都相等,所以每次就直接返回一个块的大小,它的管理方法可以是链表也可以是位图。因为不用每次查找合适的大小的内存返回,所以效率很高。
其实在实际的应用中,堆的分配算法有很多,上面的三种只是其中简单的几种,而且在实际分配中它是根据应用场景可能对应不同的分配算法,也可能是多种算法的结合。只有这样才会达到高效的这么一个原则。
malloc函数的底层实现你是否清楚的更多相关文章
- malloc 函数工作机制(转)
malloc()工作机制 malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块.然后,将 ...
- C语言 malloc函数
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. ...
- 关于malloc函数的动态分配问题
malloc函数动态分配了一个整型的内存空间,让abc都指向刚申请的空间,所以只有最后一个赋值语句的值保留在了空间里 #include<stdio.h> main() { int *a,* ...
- malloc函数详解
一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc ...
- malloc 函数到底做了什么?
请看下面的代码. 猜测结果是什么?编译通过吗? #include <stdio.h> #include <stdlib.h> int main() { ; char *ptr ...
- malloc函数和其他内存分配函数
1. 需要包含头文件:#i nclude 或 #i nclude 函数声明(函数原型): void *malloc(int size); 说明:malloc 向系统申请分配指定size个字节的内存空间 ...
- malloc函数
C语言中,使用malloc函数向内存中动态申请空间. 函数的原型是extern void *malloc(unsigned int num_bytes); 可见,函数返回的是指针类型,参数是要申请的空 ...
- 如何实现一个malloc函数
一.概述 1.malloc简介 函数所在头文件:<stdlib.h> 函数原型是:void *malloc (size_t n) 函数功能:在内存的动态存储区中分配一个长度为size的连续 ...
- C语言malloc()函数:动态分配内存空间
头文件:#include <stdlib.h> malloc() 函数用来动态地分配内存空间(如果你不了解动态内存分配,请查看:C语言动态内存分配及变量存储类别),其原型为:void* m ...
随机推荐
- UVAlive3662 Another Minimum Spanning Tree 莫队算法
就是莫队的模板题 /* Memory: 0 KB Time: 1663 MS Language: C++11 4.8.2 Result: Accepted */ #include<cstdio& ...
- SQL日志文件的作用
服务器意外关闭造成的损失.服务器意外关闭造成的损失.解决数据一致性问题.数据库时点恢复的问题,这四个常见的问题,SQL Server数据库管理员,可以通过了解数据日志文件,轻松排除故障. 当系统出现故 ...
- Her and his blog
Tonight, I read localhost8080 and some of her husband m67's blog. I found they are so geek and reall ...
- 一个HR给应届毕业生的面试建议 后悔看到的太晚了 (转)
开始之前务必记住: 黄金法则:80/20---你要承担起80%的谈话而面试官只会说20%. 白金法则:你必须试着控制面试的节奏和话题. 钻石法则:对于没有把握的问题,抛回给面试 ...
- 决策树学习(ID3)
参考:<机器学习实战> 优点:计算复杂度不高, 输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特 征数据. 缺点:可能会产生过度匹配问题. 适用数据类型:数值型和标称型. 创建分支 ...
- P2158 [SDOI2008]仪仗队 线性筛(欧拉函数和素数表)
上三角行恰好是[1,n-1]的欧拉函数 http://www.luogu.org/problem/show?pid=2158#sub //#pragma comment(linker, "/ ...
- HW5.36
import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...
- 【hdu3065】病毒侵袭持续中
题意: 求目标串中每个模式串出现几次 目标串长度<=2000000 模式串<=1000个 模式串长度<=50 题解: 这不就是AC自动机的模板题吗! 求fail树中模式串的子树中有几 ...
- HDU5781--ATM Mechine(概率dp)
题意:Alice忘记了自己银行里存了多少钱,只记得在[0,k]之间.每次取钱如果余额足够就出钱,否则警告一次,警告超过w次就会把你抓起来,在不想被警察抓起来的前提下,Alice采取最优策略,求期望取钱 ...
- mybatis代码生成器配置文件详解
mybatis代码生成器配置文件详解 更多详见 http://generator.sturgeon.mopaas.com/index.html http://generator.sturgeon.mo ...