关于heap内存分配问题追踪以及对引发coredump原因的思考

参考:
 malloc内存分配字节对齐问题
 http://blog.csdn.net/shemangui/article/details/50459102
 
1.关于分配内存操作的测试:
int getNTick()
{
        struct timespec ts;
        clock_gettime(CLOCK_MONOTONIC,&ts);
        int ns = ts.tv_sec * 1000*1000000 + ts.tv_nsec;
        return ns;
}


void  test(int mem_size)
{
        int t1=getNTick();
        char* buf = new char[mem_size];
        //memset(buf,0,mem_size);
        int t2=getNTick();
        int use1=t2-t1;


        //memset(buf,1,mem_size);
        //free(buf);


        //memset(buf,2,mem_size);
        //free(buf);
        int use2=getNTick()-t2;
        printf("-> alloc memsize:%d allocTime:%d,freeTime:%d\n",mem_size,use1,use2);
}
使用free
-> alloc memsize:10485760 allocTime:4025,freeTime:43816
-> alloc memsize:10485760 allocTime:21248,freeTime:1049
-> alloc memsize:10485760 allocTime:3243,freeTime:950
-> alloc memsize:10485760 allocTime:3237,freeTime:831
-> alloc memsize:10485760 allocTime:3138,freeTime:1288
-> alloc memsize:10485760 allocTime:3262,freeTime:848
-> alloc memsize:10485760 allocTime:3378,freeTime:1061
-> alloc memsize:10485760 allocTime:3274,freeTime:1146
-> alloc memsize:10485760 allocTime:1524,freeTime:585
-> alloc memsize:10485760 allocTime:3480,freeTime:1088
--------
-> alloc memsize:10485760 allocTime:3649,freeTime:2814
-> alloc memsize:10486784 allocTime:21639,freeTime:968
-> alloc memsize:10488832 allocTime:1581,freeTime:570
-> alloc memsize:10491904 allocTime:11294,freeTime:1006
-> alloc memsize:10496000 allocTime:12464,freeTime:1158
-> alloc memsize:10501120 allocTime:11743,freeTime:1077
-> alloc memsize:10507264 allocTime:11691,freeTime:1381
-> alloc memsize:10514432 allocTime:5474,freeTime:408
-> alloc memsize:10522624 allocTime:11282,freeTime:899
-> alloc memsize:10531840 allocTime:10269,freeTime:946

不使用free
-> alloc memsize:10485760 allocTime:3594,freeTime:33
-> alloc memsize:10485760 allocTime:22147,freeTime:35
-> alloc memsize:10485760 allocTime:19764,freeTime:92
-> alloc memsize:10485760 allocTime:24867,freeTime:108
-> alloc memsize:10485760 allocTime:24288,freeTime:130
-> alloc memsize:10485760 allocTime:25619,freeTime:122
-> alloc memsize:10485760 allocTime:10792,freeTime:44
-> alloc memsize:10485760 allocTime:22506,freeTime:141
-> alloc memsize:10485760 allocTime:22518,freeTime:108

-> alloc memsize:10485760 allocTime:23545,freeTime:121

-------

-> alloc memsize:10485760 allocTime:3675,freeTime:42
-> alloc memsize:10486784 allocTime:23219,freeTime:94
-> alloc memsize:10488832 allocTime:22277,freeTime:171
-> alloc memsize:10491904 allocTime:25335,freeTime:135
-> alloc memsize:10496000 allocTime:16881,freeTime:63
-> alloc memsize:10501120 allocTime:27219,freeTime:136
-> alloc memsize:10507264 allocTime:20322,freeTime:90
-> alloc memsize:10514432 allocTime:23304,freeTime:95
-> alloc memsize:10522624 allocTime:22770,freeTime:151
-> alloc memsize:10531840 allocTime:23454,freeTime:91


测试结论:
1.malloc在首次申请内存时较快(这是不是因为程序启动前就Break指针就指在一个合适的MappingArea?),
 第二次分配会变慢(初次Break指的范围的MappingArea不够用了,需要扩展Mapping,耗时?)
 如果前面调用free过一次相近的内存块,那么在此malloc内存块时,就会变得快一点,大概加速了5-10倍;
 
 这验证了malloc内部有内存块缓存功能,并没有还回给OS,malloc内部维护这一个空闲列表进行内存分配的加速处理。
  


2.关于释放操作的测试:  
指令序列:
char* buf = (char*) malloc(mem_size);
free(buf);
free(buf);
操作结果:程序并没有崩溃;
---------------------------------
char* buf = new char[mem_size]
free(buf);
free(buf);
操作结果:double free or corruption 导致崩溃;
-----------------------------------
char* buf = (char*) malloc(mem_size);
delete(buf);
delete(buf);
操作结果:double free or corruption 导致崩溃;

测试推论:

1.new操作,在malloc的基础上,应该增加了一些状态判断字段,使得释放内存操作时,会主动查看这些标志来判断是否是重复释放,以abort进程的方式防御非法指令;

 2.这验证了new一定与delete匹配,malloc与free匹配,不要交叉使用,虽然有时候并没有问题产生。

3.其实把buf 执行free之后,buf还是可以照常使用,没问题;但是不建议做,这会引发相同内存块被其他线程分配得到,而产生不可预测的风险。


3.关于Heap内存的一次分配的,上界,下界,地址分配规律,地址对齐问题的测试:

			
void test2()
{
        char* buf=new char[1024];
        for(int i;i<5000;i++)
        {
                buf[i]=0;
                printf("%d %p\n",i,&buf[i]);
        }
		/*
		Program received signal SIGABRT, Aborted.
		
		Assertion `(old_top == initial_top (av) && old_size == 0) || 
		((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && 
		((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
		*/
}
	
		


void test3()
{
        char* buf1=(char*)malloc(1024);
        char* buf2=(char*)malloc(1024);
        char* buf3=(char*)malloc(1024);
        char* buf4=(char*)malloc(1024);
        printf("buf1:%p\n",buf1);
        printf("buf2:%p\n",buf2);
        printf("buf3:%p\n",buf3);
        printf("buf4:%p\n",buf4);
        free(buf4);
        char* buf5=(char*)malloc(1024);
        printf("buf5:%p\n",buf5);
		
		//结果
		//buf1:0x1f70c20
		//buf2:0x1f71030
		//buf3:0x1f71440
		//buf4:0x1f71850
		//buf5:0x1867850 与buf4一样,说明了free只是把block缓存到空闲列表,供下次需要直接取出;
		//buf1、buf2相距1040字节,并不是相距1024字节
		
		
}
		
		
		
void test4()
{
        srand(time(NULL)+ getNTick()%123243555 );
        int n=rand()%102232287;
        char* buf=(char*)malloc(n);
        void* p = buf;
        long  p2 = (long)p;
        float f = float(p2)/float(16);
        printf("%d %p %f\n",n,buf,f);
		//验证分配的地址以16字节对齐


}


void test2()
{
        void* p1=sbrk(0);
        char* buf=new char[1024];
        printf("buf:%p\n",buf);
        void* p2=       sbrk(0);
        printf("brk:%p    brk2:%p\n",p1,p2);
        char* buf2 = new char[1024*127];
        printf("brk3:%p  buf2: %p\n", sbrk(0),buf2);
        char* buf4 = new char[1024*180];
         printf("brk4:%p  buf4: %p\n", sbrk(0),buf4);


		/*
		buf:0x2125c20
brk:0x2146000    brk2:0x2146000
brk3:0x2167000  buf2: 0x2126440
brk4:0x2167000  buf4: 0x7f8ebf271010
		推论:程序一启动编译器就把Break指针指向0x2146000,计算0x2146000-0x2125c20=132064即为进程预备了大约128K的Heap空间<可以测试
		出可用的heap大约是200K>;
		如果剩余找不到一个内存size满足预分配的内存,break指针就偏移4096字节进行扩展;
		如果某次要分配的内存的大约200K以上,那么进行使用mmap得到大内存块;可以发现0x7f8ebf271010明显区别于前面的地址形式;
		
		brk:0x2146000与4096对齐; 
		*/
}


void test4()
{
        printf("test4\n");
        long stack=0x00007FFFFFFFFFFF;
        long s=0x2125c20;
        void* p = sbrk(0);
        char* p2 = (char*)p;
        printf("111\n");
        long* pz = (long*)(p2-1024*32);
        printf("222\n");
        *pz=1;


        pz=(long*)s;
        *pz=2;
		
		/*
			程序启动就会一段预先mapping好的内存块,大约200K;如果指定指针操作一块不在mapping范围的地址,或者非userspace区域的地址,就会出现段错误;
		
		*/


}

4.总结:引起Coredump错误的原因如下:

1.尝试写数据到一块没有mapping好的地址,或者非userspace的地址、因此产生段错误;

举例说明:强制操作一块不确定地址的内存;使用未初始化的内存;写NULL指针;循环操作或者buf+offset被偏移到了一个非mapping的地址等;

2.因为程序的断言条件不被满足,而主动abort产生的崩溃,使得进程被终止;比如重复free,divzero,stackoverflow等;


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值