动态存储管理_free崩溃

版权声明:私藏源代码是违反人性的罪恶行为!博客转载无需告知,学无止境。 https://blog.csdn.net/qq_41822235/article/details/84193884

一、 生存期

从变量值的存在时间(生存期)来观察。有的变量在程序运行的整个过程都是存在的,而有的变量则是在调用其所在函数才临时分配存储单元,而在函数调用结束后该存储单元就马上释放了,变量就不存在了。

1.1 静态存储方式

是指在程序运行期间由系统分配固定的存储空间的方式。

1.2 动态存储方式

是指在程序运行期间根据需要进行动态的分配存储空间的方式。下面我们讨论一下free因何崩溃。

二、 free崩溃

void __cdecl free(
    _Pre_maybenull_ _Post_invalid_ void* _Block
    );

本声明来自VS2017, 从声明我们可以看到,free函数的参数只有1个——无类型的指针。这就带来一个问题:释放申请的空间,不借助其他参数,操作系统如何知晓用完待释放的空间的大小呢?既然函数传参时不能体现,肯定就在别处解决了。需要留心边界标志法——大概含义就是申请下来的空间还要有头部、尾部:头部用于记录大小,尾部用于碎片整理过程(小的空闲碎片合并成大的空闲碎片)。free因何越界原因就很清楚了,极有可能是因为破坏了边界信息

2.1 上越界

#include<malloc.h>
#include<stdio.h>
#include<assert.h>

int main()
{
	int *p = (int*)malloc(10);	//申请10byte的空间
	assert(NULL != p);
	p++;
	free(p);    //p向上偏移进行解引用取出块的大小时发生错误    段错误
    return 0;
}

2.2 下越界

#include<malloc.h>
#include<stdio.h>
#include<assert.h>

int main()
{
	int *p = (int*)malloc(10);	//申请10byte的空间
	assert(NULL != p);
	for (int i = 0; i < 10 + 1; ++i)    //故意设置成数组访问越界
	{
		p[i] = 1;
	}
	free(p);    //下越界
	return 0;
}

2.3 重复释放同一块空间

#include<malloc.h>
#include<stdio.h>
#include<assert.h>

int main()
{
	int *p = (int*)malloc(10);	//申请10byte的空间
	assert(NULL != p);
	free(p);
	free(p);    //第二次,属于重复free
	return 0;
}

三、 realloc 

对于动态内存开辟这个行为:我们不会去讨论生存期或者地址高低,前者不必要是因为动态开辟的内存会一直存在 until 主动free或者程序结束;后者是因虚拟地址空间和段页机制的存在,先申请的内存不一定位于低地址,后申请的内存不一定位于高地址。

3.1 情况1

#include<malloc.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

int main()
{
	int *p = (int*)malloc(10);	//申请10byte的空间
	assert(NULL != p);
	printf("%x\n", p);

	int *q = (int*)malloc(10);    //防止在p的尾部追加空间

	p = (int*)realloc(p, 200);	//原有空间释放,申请200byte的空间
	printf("%x\n", p);
	
    free(p);
	return 0;
}

3.2 情况2 

#include<malloc.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

int main()
{
	int *p = (int*)malloc(10);	//申请10byte的空间
	assert(NULL != p);
	printf("%x\n", p);

	int *q = (int*)malloc(10);	//防止在p尾部添加空间

	p = (int*)realloc(p, 6);	//原有空间释放,申请6byte的空间
	
    p[8] = 100;    
    
	printf("%x\n", p);
	free(p);    //如果是新申请的空间,越界时将崩溃,但是最后验证了并没有崩溃
	return 0;
}

3.3 小结

void* __cdecl realloc(
    _Pre_maybenull_ _Post_invalid_ void*  _Block,
    _In_ _CRT_GUARDOVERFLOW        size_t _Size
    );

声明来自VS2017,_Size指的是新空间的大小。策略是的:1 如果再分配的空间 ≤ 原有的空间,realloc实际上是一个空壳函数,什么也不做,申请下来的空间还是原来的空间,但是这一过程对用户透明。这一点在3.2节得到了验证——并没有执行内存紧缩,以空间换区时间,回收内存是一件很麻烦的事情;2 如果再分配的空间>原有空间,可能会在原有空间后面追加一块空间;也可能是先释放原有空间,然后新申请一块空间。后者是更为常见的,因为无法确保原有空间后是否还有足够的空间。

猜你喜欢

转载自blog.csdn.net/qq_41822235/article/details/84193884