堆溢出原理

堆(heap)也是一种基本的数据结构,它可由开发人员自行分配、释放堆是向高地址扩展的,不连续的内存区域。由于系统使用链表来管理空闲的内存块,堆自然是不连续的。 其中,链表的遍历是由低地址向高地址进行的。堆的存储结构如图:
堆溢出原理_第1张图片
在标准C语言上,使用malloc等内存分配函数获取内存即是从堆中分配内存,而在一个函数体中例如定义一个数组之类的操作是从栈中分配内存。从堆中分配的内存需要程序员手动释放,如果不释放,而系统内存管理器又不自动回收这些堆内存的话(实现这一项功能的系统很少)
,那就一直被占用。如果一直申请堆内存,而不释放,内存会越来越少,很明显的结果是系统变慢或者申请不到新的堆内存。而过度的申请堆内存(可以试试在函数中申请一个1G的数组!),会导致堆被压爆,结果是灾难性的。
我们掌握堆内存的权柄就是返回的指针,一旦丢掉了指针,便无法在我们视野内释放它。这便是内存泄露。而如果在函数中申请一个数组,在函数体外调用使用这块堆内存,结果将无法预测。 我们知道在c/c++ 中定义的数组大小必需要事先定义好,他们通常是分配在静态内存空间或者是在栈内存空间内的,但是在实际工作中,我们有时候却需要动态的为数组分配大小,这时就要用到堆内存分配的概念。在堆内存分配时首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。堆内存是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆内存的大小受限于计算机系统中有效的虚拟内存。由此可见,堆内存获得的空间比较灵活,也比较大。堆内存是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,它直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

你可能感兴趣的:(pwn)