C 高级编程 2 内存管理
2016-05-19 21:09
337 查看
理解malloc的工作原理: malloc使用一个数据结构(链表)来维护分配的空间。链表的构成: 分配的空间、上一个空间的地址、下一个空间的地址、以及本空间的信息等。 对malloc分配的空间不要越界访问, 因为容易破坏后台的链表维护结构,导致malloc/free/calloc/realloc不正常工作。 定位分配 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<new> intmain() { chara[20]; int*p=new(a)int; return0; } 深入理解LINUX虚拟内存管理 #include<stdio.h> intadd(inta,intb) { returna+b; } intman() { //int(*fun)(int)=(int(*)(int))add; typedefint(*fun)(int); funf=(fun)add; intr=fun(20); printf("%d\n",r); }
sbrk(0):如果是第一次调用sbrk函数,即内部变量为null,参数值为0,那么返回值为非映射页面的首地址 参数值非0,那么返回的已映射页的首地址 5.函数调用空间的分配与释放与分配 总结: 1.C:函数执行的时候有自己的临时stack c++:函数执行的时候有自己的临时stack+对象stack 2.函数的参数在临时stack, 3.通过积存器返回值(使用返回值顺数据) 4.通赤参数的返回值.(参数必须是指针) 指针指向的区域必须事先分配 5。如果参数返回指针,参数就是双指针. --------------------------------------------------- intadd(int*a,int*b) {return*a+*b; } main() { inta=20; intb=30; intr=add(&a,&b); printf("%d\n",r); } --------------------------------------------------------- 5.2.__stdcall__cdecl__fastcall 1.决定函数stack压stack参数顺序。 2.决定函数stack清空方式 3.决定了函数的名字转换方式.(函数名重写修改,C,C++都不同) 4.__attribute__不支持X64 #include<stdio.h> int__attribute__((stdcall))add(int*a,int*b) { return(*a)+(*b); } main() { inta=20; intb=30; intr=add(&a,&b); printf("%d\n",r); } gcctest.c-m32-S [root@monitor~]#cattest.s .file"test.c" .text .globladd .typeadd,@function add: pushl%ebp movl%esp,%ebp movl8(%ebp),%eax movl(%eax),%edx movl12(%ebp),%eax movl(%eax),%eax leal(%edx,%eax),%eax popl%ebp ret$8 .sizeadd,.-add .section.rodata .LC0: .string"%d\n" .text .globlmain .typemain,@function main: leal4(%esp),%ecx andl$-16,%esp pushl-4(%ecx) pushl%ebp movl%esp,%ebp pushl%ecx subl$36,%esp movl$20,-16(%ebp) movl$30,-20(%ebp) leal-20(%ebp),%eax movl%eax,4(%esp) leal-16(%ebp),%eax movl%eax,(%esp) calladd subl$8,%esp movl%eax,-12(%ebp) movl$.LC0,%eax movl-12(%ebp),%edx movl%edx,4(%esp) movl%eax,(%esp) callprintf movl-4(%ebp),%ecx leave leal-4(%ecx),%esp ret .sizemain,.-main .ident"GCC:(GNU)4.4.720120313(RedHat4.4.7-16)" .section.note.GNU-stack,"",@progbits [root@monitor~]#gcctest.c-m64-S test.c:4:warning:‘stdcall’attributeignored ------------------------------------------------------ #include<stdio.h> int__attribute__((cdecl))add(int*a,int*b) { return(*a)+(*b); } main() { inta=20; intb=30; intr=add(&a,&b); printf("%d\n",r); } [root@monitor~]#gcctest.c-m32-S [root@monitor~]#cattest.s .file"test.c" .text .globladd .typeadd,@function add: pushl%ebp movl%esp,%ebp movl8(%ebp),%eax movl(%eax),%edx movl12(%ebp),%eax movl(%eax),%eax leal(%edx,%eax),%eax popl%ebp ret .sizeadd,.-add .section.rodata .LC0: .string"%d\n" .text .globlmain .typemain,@function main: pushl%ebp movl%esp,%ebp andl$-16,%esp subl$32,%esp movl$20,24(%esp) movl$30,20(%esp) leal20(%esp),%eax movl%eax,4(%esp) leal24(%esp),%eax movl%eax,(%esp) calladd movl%eax,28(%esp) movl$.LC0,%eax movl28(%esp),%edx movl%edx,4(%esp) movl%eax,(%esp) callprintf leave ret .sizemain,.-main .ident"GCC:(GNU)4.4.720120313(RedHat4.4.7-16)" .section.note.GNU-stack,"",@progbits [root@monitor~]#gcctest.c-m64-S test.c:4:warning:‘cdecl’attributeignored ---------------------------------------------------------------- #include<stdio.h> int__attribute__((fastcall))add(int*a,int*b) { return(*a)+(*b); } main() { inta=20; intb=30; intr=add(&a,&b); printf("%d\n",r); } [root@monitor~]#gcctest.c-m64-S test.c:4:warning:‘fastcall’attributeignored ---------------------------------------------------------------------- intadd(inta,intb) { returna+b; } intmain() { add(10,20); } [root@monitor~]#vitest1.c intadd(inta,intb) { returna+b; } intmain() { add(10,20); } nm:test1.c:Fileformatnotrecognized [root@monitor~]#gcc-m32test.c-otest [root@monitor~]#nmtest 080495acd_DYNAMIC 08049678d_GLOBAL_OFFSET_TABLE_ 080484ecR_IO_stdin_used w_Jv_RegisterClasses 0804959cd__CTOR_END__ 08049598d__CTOR_LIST__ 080495a4D__DTOR_END__ 080495a0d__DTOR_LIST__ 08048594r__FRAME_END__ 080495a8d__JCR_END__ 080495a8d__JCR_LIST__ 08049694A__bss_start 08049690D__data_start 080484a0t__do_global_ctors_aux 08048340t__do_global_dtors_aux 080484f0R__dso_handle w__gmon_start__ 0804849aT__i686.get_pc_thunk.bx 08049598d__init_array_end 08049598d__init_array_start 08048430T__libc_csu_fini 08048440T__libc_csu_init U__libc_start_main@@GLIBC_2.0 08049694A_edata 0804969cA_end 080484ccT_fini 080484e8R_fp_hw 08048294T_init 08048310T_start 080483c4Tadd 08049694bcompleted.5989 08049690Wdata_start 08049698bdtor_idx.5991 080483a0tframe_dummy 080483dfTmain Uprintf@@GLIBC_2.0 --------------------------------------------------------------------------- [root@monitor~]#vitest.c intadd(int,int); intadd(inta,intb) { returna+b; } intmain() {intr; r=add(10,20); return1; } [root@monitor~]#g++test.c-otest [root@monitor~]#nmtest 00000000006007a0d_DYNAMIC 0000000000600968d_GLOBAL_OFFSET_TABLE_ 0000000000400678R_IO_stdin_used w_Jv_RegisterClasses 0000000000400554T_Z3addii 0000000000600780d__CTOR_END__ 0000000000600778d__CTOR_LIST__ 0000000000600790D__DTOR_END__ 0000000000600788d__DTOR_LIST__ 0000000000400770r__FRAME_END__ 0000000000600798d__JCR_END__ 0000000000600798d__JCR_LIST__ 0000000000600994A__bss_start 0000000000600990D__data_start 0000000000400630t__do_global_ctors_aux 00000000004004c0t__do_global_dtors_aux 0000000000400680R__dso_handle w__gmon_start__ U__gxx_personality_v0@@CXXABI_1.3 0000000000600774d__init_array_end 0000000000600774d__init_array_start 0000000000400590T__libc_csu_fini 00000000004005a0T__libc_csu_init U__libc_start_main@@GLIBC_2.2.5 0000000000600994A_edata 00000000006009a8A_end 0000000000400668T_fini 0000000000400428T_init 0000000000400470T_start 000000000040049ctcall_gmon_start 0000000000600998bcompleted.6349 0000000000600990Wdata_start 00000000006009a0bdtor_idx.6351 0000000000400530tframe_dummy 0000000000400569Tmain -------------------------------------------------------- 6.farnearhuge指针(windows) near16 far32 huge综合 7.虚拟内存 1.一个程序不能访问另一个程序指向的空间 2.每个程序的开始地址0x80084000 3.程序使用的地址不是物理,而不能逻辑地址 4.辑辑编号是使用int4字节整型地址 (0,4294967296) 每个程序提代了4G的访问能力 5.针对进程的(虚拟内存<---->物理内存) 这样进程有逻辑上的地址空间,屏蔽了真实内内存使用状况,由MMU后台管理映射 进程只操作虚拟地址,禁止访问物理地址,有助于系统稳定 6.逻辑地址与物理地址关联 有映射才可访问,如果访问没有映射地址,出现段错误 7.虚拟地址在映射的时候有个映射单位4K(16进制的1000,称为内存页) EG:malloc(1),只少分配4K的内存页, 段错误:无效访问 合法访问:比如malloc分配的空间之外的空间访问,不会出现段错误,但不是合法访问, 可能修改了其他变量值 8.虚拟内存的分配 stack:编绎器自动生成代码维护 heap:地址是否映射,映射的空间是否被管理 1.brk/sbrk内存映射函数 man节关键字 1-8节 1:linuxshell命令ls 2:系统函数brk 3.标准C文档fopen 7.系统的编程帮助 man7tcp man7icmp man7udp man7socket 分配空间,释放空间: intbrk(void*end);分配空间,释放空间 void*sbrk(intsize);返回空间地址 应用: 1使用sbrk他配空间 2使用sbrk得到没有映射的虚拟地址 3使用brk他配空间 4使用brk释放空间 sbrk(intsize) sbrk与brk后台系统维护一个指针。 指针默认是null 调用sbrk,断定指针是否是0, 如果是0,返回大块空闲空间的首地址并初始化指针,同时把后台指针+size 如果不是0,返回指针,并且把指针位置+SIZE --------------------------------------------------------------------- #include<stdio.h> #include<stdlib.h> main() { int*p1=sbrk(4); int*p2=sbrk(4); int*p3=sbrk(4); int*p4=sbrk(4); int*p5=sbrk(4); printf("%p\n",p1); printf("%p\n",p2); printf("%p\n",p3); printf("%p\n",p4); printf("%p\n",p4); printf("%d\n",getpid()); while(1); } [root@monitor~]#gcctest.c-m32-otest [root@monitor~]#./test 0x9e03000 0x9e03004 0x9e03008 0x9e0300c 0x9e03010 10148 //分配是有序的4个字节 [root@monitor10138]#cd/proc/10148 [root@monitor10148]#catmaps 00155000-002e5000r-xp00000000ca:01396343/lib/libc-2.12.so 002e5000-002e6000---p00190000ca:01396343/lib/libc-2.12.so 002e6000-002e8000r--p00190000ca:01396343/lib/libc-2.12.so 002e8000-002e9000rw-p00192000ca:01396343/lib/libc-2.12.so 002e9000-002ec000rw-p0000000000:000 00ba3000-00bc1000r-xp00000000ca:01396396/lib/ld-2.12.so 00bc1000-00bc2000r--p0001d000ca:01396396/lib/ld-2.12.so 00bc2000-00bc3000rw-p0001e000ca:01396396/lib/ld-2.12.so 00cd7000-00cd8000r-xp0000000000:000[vdso] 08048000-08049000r-xp00000000ca:011065171/root/test 08049000-0804a000rw-p00000000ca:011065171/root/test 09e03000-09e04000rw-p0000000000:000[heap] f775a000-f775b000rw-p0000000000:000 f7762000-f7764000rw-p0000000000:000 ff9c0000-ff9d5000rw-p0000000000:000[stack] ------------------------------------------------------------------------------------------ #include<stdio.h> #include<stdlib.h> main() {int*p1=sbrk(0);返回没有映射地址,因为0没有分配空间,即逻辑到物理关联没有建立 int*p1=sbrk(4);//返回空闲首地址(位于段)4K页倍数系统分配单元,并修改后台指针为+SIZE int*(p1+1023);正常,但不合法 int*(p1+1024);段错误 } ------------------------------------------------------------------------------- 后台维护一个后台变量。初值为NULL #include<stdio.h> #include<stdlib.h> main() {int*p1=sbrk(4);//页首地址(0-3) int*p2=sbrk(200);//(4,199) int*p3=sbrk(0);//(200) printf("%p\n",p1); pirntf("%p\n",p2); printf("%p\n",p3); printf("%d",getpid()); while(1); } [root@monitor~]#./test 0x9b63000 0x9b63004 0x9b630cc200+4=204 [root@monitor10211]#catmaps 00ba3000-00bc1000r-xp00000000ca:01396396/lib/ld-2.12.so 00bc1000-00bc2000r--p0001d000ca:01396396/lib/ld-2.12.so 00bc2000-00bc3000rw-p0001e000ca:01396396/lib/ld-2.12.so 00bc5000-00d55000r-xp00000000ca:01396343/lib/libc-2.12.so 00d55000-00d56000---p00190000ca:01396343/lib/libc-2.12.so 00d56000-00d58000r--p00190000ca:01396343/lib/libc-2.12.so 00d58000-00d59000rw-p00192000ca:01396343/lib/libc-2.12.so 00d59000-00d5c000rw-p0000000000:000 00d7c000-00d7d000r-xp0000000000:000[vdso] 08048000-08049000r-xp00000000ca:011065171/root/test 08049000-0804a000rw-p00000000ca:011065171/root/test 09b63000-09b64000rw-p0000000000:000[heap] f7706000-f7707000rw-p0000000000:000 f770e000-f7710000rw-p0000000000:000 ff9d7000-ff9ec000rw-p0000000000:000[stack] ------------------------------------------------------------------------------------------- 释放空间:SIZE为负,释放空间 #include<stdio.h> #include<stdlib.h> main(){ int*p1=sbrk(4); int*p2=sbrk(200); int*p3=sbrk(-4); int*p4=sbrk(-4); int*p5=sbrk(-4); printf("%p\n,p1"); printf("%p\n",p2); printf("%p\n",p3); printf("%p\n",p4); printf("%p\n",p5); printf("%d\n",getpid()); } [root@monitor~]#./test 0x98d3000 0x98d3004 0x98d30cc 0x98d30c8 0x98d30c4 10245 ------------------------------------------------------------------------ #include<stdio.h> #include<stdlib.h> main() { //brk绝对移动 int*p=sbrk(0); brk(p+1);//P+1是地址后台地址 *p=800; brk(p);移动到P处,后台地址 *p=99;//Segmentationfault } [root@monitor~]#./test Segmentationfault ---------------------------------------- #include<stdio.h> #include<stdlib.h> main() { int*a=malloc(4); *a=9999; printf("%p\n",a); while(1); } [root@monitor~]#./test 0x209f010 #include<stdio.h> #include<stdlib.h> main() { int*a=(int*)0x209f010; *a=9999; printf("%d\n",*a); while(1); } [root@monitor~]#./test 0x1cce010 ------------------------------------- [root@monitor~]#manbrk BRK(2)LinuxProgrammer’sManualBRK(2) NAME brk,sbrk-changedatasegmentsize SYNOPSIS #include<unistd.h> intbrk(void*addr);// void*sbrk(intptr_tincrement); FeatureTestMacroRequirementsforglibc(seefeature_test_macros(7)): brk(),sbrk():_BSD_SOURCE||_SVID_SOURCE||_XOPEN_SOURCE>=500 DESCRIPTION brk()andsbrk()changethelocationoftheprogrambreak,whichdefinestheendoftheprocess’sdataseg- ment(i.e.,theprogrambreakisthefirstlocationaftertheendoftheuninitializeddatasegment). Increasingtheprogrambreakhastheeffectofallocatingmemorytotheprocess;decreasingthebreakdeallo- catesmemory. brk()setstheendofthedatasegmenttothevaluespecifiedbyaddr,whenthatvalueisreasonable,the systemhasenoughmemory,andtheprocessdoesnotexceeditsmaximumdatasize(seesetrlimit(2)). sbrk()incrementstheprogram’sdataspacebyincrementbytes.Callingsbrk()withanincrementof0canbe usedtofindthecurrentlocationoftheprogrambreak. RETURNVALUE Onsuccess,brk()returnszero.Onerror,-1isreturned,anderrnoissettoENOMEM.(ButseeLinuxNotes below.) Onsuccess,sbrk()returnsthepreviousprogrambreak.(Ifthebreakwasincreased,thenthisvalueisa pointertothestartofthenewlyallocatedmemory).Onerror,(void*)-1isreturned,anderrnoissetto ENOMEM. 1.#include<stdio.h> #include<unistd.h> main() { int*p=sbrk(4);//分配4个字节的整数空间 *p=8888; printf("%d\n",*p); } [root@monitor~]#./test 8888 2.#include<stdio.h> #include<unistd.h> main() { int*p=sbrk(0); *p=8888; } 3. #include<stdio.h> #include<unistd.h> main() { int*p=sbrk(0);//返回没有映射的空间首地址 brk(p+1);//P+1分配空间 *p=8888;//赋值 brk(p);// *p=8888; } ------------------------------------------------------------------------------- http://blog.csdn.net/sgbfblog/article/details/7772153http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/ intbrk(void*addr);//后台指针移动 void*sbrk(intptr_tincrement);//后台一个地址值+increment brk()这个函数的参数是一个地址,假如你已经知道了堆的起始地址,还有堆的大小, 那么你就可以据此修改brk()中的地址参数已达到调整堆的目的。 实际上,在应用程序中,基本不直接使用这两个函数,取而代之的是malloc()一类函数,这一类库函数的执行效率会更高。 还需要注意一点,当使用malloc()分配过大的空间,比如超出0x20ff8这个常数(在我的系统(Fedora15)上是这样, 别的系统可能会有变)时,malloc不再从堆中分配空间,而是使用mmap()这个系统调用从映射区寻找可用的内存空间 #include<stdio.h> #include<unistd.h> intmain() { /*分配10个字节的空间,返回该空间的首地址*/ void*p=sbrk(12); void*p2=sbrk(4); void*p3=sbrk(4); void*p4=sbrk(4); printf("p=%p\n",p); printf("p2=%p\n",p2); printf("p3=%p\n",p3); printf("p4=%p\n",p4); /*用参数为0来获取未分配空间的开始位置*/ void*p0=sbrk(0); printf("p0=%p\n",p0); void*p5=sbrk(-4); printf("p5=%p\n",p5); printf("pid=%d\n",getpid()); sleep(10); /*当释放到一个页面的开始位置时,整个页面会被操作系统回收*/ sbrk(-20); while(1); } [root@monitor~]#gcctest1.c-m32-otest [root@monitor~]#./test p=0x8e2c000 p2=0x8e2c00c p3=0x8e2c010 p4=0x8e2c014 p0=0x8e2c018 p5=0x8e2c018 pid=10679 http://blog.csdn.net/sgbfblog/article/details/7772153http://www.cnblogs.com/runnyu/tag/apue/ http://bbs.chinaunix.net/thread-4066412-1-1.html 内存分配: 智能指针 stl malloc: new brk/sbrk:结构简单,数据量大 异常处理: intbrk(void*) void*sbrk() 如果成功brk返加0,sbrk返加指针 失败brk返回-1,sbrk返回(void*)-1 #include<string.h> #include<errno.h> #include<stdlib.h> #include<unistd.h> #include<stdio.h> externinterrno;//3种 intmain() { void*p=sbrk(1000000*10000); if(p==(void*)-1) {printf("err!\n"); perror("hello!");//1种 printf("%m\n");//2种 printf("::%s\n",strerror(errno));//3种 } } string:string.hcstring mem:mallocmemsetmemcmpmemcpybzero error: io: time: cast:
[root@monitor~]#vitest.c
#include<stdio.h>
#include<stdlib.h>
main()
{
char*p3=0;
int*p=sbrk(4);
int*p2=sbrk(4);
int*p1=brk(p2);
int*p4=sbrk(0);
int*p5=sbrk(4);
printf("%p\n",p);
printf("%p\n",p2);
printf("%p\n",p1);
printf("%p\n",p4);
printf("%p\n",p5);
*p3=10;
[root@monitor~]#./test
0x79a000
0x79a004
(nil)
0x79a004
0x79a004
Segmentationfault
相关文章推荐
- PHP 代码跟踪
- 【C语言】C语言储存类型关键字详细解析
- base64加密原理代码实现
- php CI框架搭建(一)
- 深入理解C++的动态绑定和静态绑定
- 认识Java Core和Heap Dump
- halcon与C#混合编程
- L1-005. 考试座位号(C++)
- [Java]HashMap源码分析
- POJ 1001 Exponentiation(大数幂Java实现)
- java抽象类,接口
- php页面用include引入header.php出现头部上边有一行空白
- C++类型安全
- YII的lazy loading
- faster rcnn的源码理解(一)SmoothL1LossLayer论文与代码的结合理解
- matlab 字符隐藏
- C# j基本操作-拷贝文件夹的所有内容到另一个文件夹内: 复制代码 1 public static void CopyDir(string srcPath, string实现文件夹的复制以及删除
- python join与split函数的用法举例
- Struts2_ActionSupport和通配符映射和动态方法调用
- JAVA设计模式(19):行为型-观察者模式(Observer)