理解malloc的工作原理:

malloc使用一个数据结构(链表)来维护分配的空间。链表的构成:
分配的空间、上一个空间的地址、下一个空间的地址、以及本空间的信息等。
对malloc分配的空间不要越界访问,
因为容易破坏后台的链表维护结构,导致malloc/free/calloc/realloc不正常工作。 定位分配
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <new>
int main()
{ char a[];
int *p=new(a) int; return ; } 深入理解LINUX虚拟内存管理
#include <stdio.h>
int add(int a, int b)
{ return a+b; }
int man() { //int (*fun)(int)=(int(*)(int))add;
typedef int(*fun)(int);
fun f=(fun)add;
int r=fun();
printf("%d\n",r); }


sbrk(0):如果是第一次调用sbrk函数,即内部变量为null,参数值为0,那么返回值为非映射页面的首地址

参数值非0,那么返回的已映射页的首地址



  .函数调用空间的分配与释放与分配
总结:
.C :函数执行的时候有自己的临时stack
c++:函数执行的时候有自己的临时stack+对象stack
.函数的参数在临时stack,
.通过积存器返回值 (使用返回值顺数据)
.通赤参数的返回值.(参数必须是指针)
指针指向的区域必须事先分配
。如果参数返回指针,参数就是双指针. ---------------------------------------------------
int add(int *a,int *b)
{ return *a+*b;
}
main()
{
int a=;
int b=;
int r=add(&a,&b);
printf("%d\n",r); }
---------------------------------------------------------
5.2. __stdcall __cdecl __fastcall
.决定函数stack 压stack 参数顺序。
.决定函数stack清空方式
.决定了函数的名字转换方式.(函数名重写修改 ,C,C++都不同)
.__attribute__ 不支持X64 #include <stdio.h>
int __attribute__((stdcall)) add( int *a,int *b)
{
return (*a)+(*b); }
main()
{ int a=;
int b=;
int r=add(&a,&b);
printf("%d\n",r); } gcc test.c -m32 -S [root@monitor ~]# cat test.s
.file "test.c"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax
movl (%eax), %edx
movl (%ebp), %eax
movl (%eax), %eax
leal (%edx,%eax), %eax
popl %ebp
ret $
.size add, .-add
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
leal (%esp), %ecx
andl $-, %esp
pushl -(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $, %esp
movl $, -(%ebp)
movl $, -(%ebp)
leal -(%ebp), %eax
movl %eax, (%esp)
leal -(%ebp), %eax
movl %eax, (%esp)
call add
subl $, %esp
movl %eax, -(%ebp)
movl $.LC0, %eax
movl -(%ebp), %edx
movl %edx, (%esp)
movl %eax, (%esp)
call printf
movl -(%ebp), %ecx
leave
leal -(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
.section .note.GNU-stack,"",@progbits [root@monitor ~]# gcc test.c -m64 -S
test.c:: warning: ‘stdcall’ attribute ignored ------------------------------------------------------ #include <stdio.h>
int __attribute__((cdecl)) add( int *a,int *b)
{
return (*a)+(*b); }
main()
{ int a=;
int b=;
int r=add(&a,&b);
printf("%d\n",r); } [root@monitor ~]# gcc test.c -m32 -S
[root@monitor ~]# cat test.s
.file "test.c"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax
movl (%eax), %edx
movl (%ebp), %eax
movl (%eax), %eax
leal (%edx,%eax), %eax
popl %ebp
ret
.size add, .-add
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-, %esp
subl $, %esp
movl $, (%esp)
movl $, (%esp)
leal (%esp), %eax
movl %eax, (%esp)
leal (%esp), %eax
movl %eax, (%esp)
call add
movl %eax, (%esp)
movl $.LC0, %eax
movl (%esp), %edx
movl %edx, (%esp)
movl %eax, (%esp)
call printf
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
.section .note.GNU-stack,"",@progbits [root@monitor ~]# gcc test.c -m64 -S
test.c:: warning: ‘cdecl’ attribute ignored
----------------------------------------------------------------
#include <stdio.h>
int __attribute__((fastcall)) add( int *a,int *b)
{
return (*a)+(*b); }
main()
{ int a=;
int b=;
int r=add(&a,&b);
printf("%d\n",r); } [root@monitor ~]# gcc test.c -m64 -S
test.c:: warning: ‘fastcall’ attribute ignored ----------------------------------------------------------------------
int add( int a ,int b)
{ return a+b;
} int main()
{ add(,);
} [root@monitor ~]# vi test1.c int add( int a ,int b)
{ return a+b;
} int main()
{ add(,);
} nm: test1.c: File format not recognized
[root@monitor ~]# gcc -m32 test.c -o test
[root@monitor ~]# nm test
080495ac d _DYNAMIC
d _GLOBAL_OFFSET_TABLE_
080484ec R _IO_stdin_used
w _Jv_RegisterClasses
0804959c d __CTOR_END__
d __CTOR_LIST__
080495a4 D __DTOR_END__
080495a0 d __DTOR_LIST__
r __FRAME_END__
080495a8 d __JCR_END__
080495a8 d __JCR_LIST__
A __bss_start
D __data_start
080484a0 t __do_global_ctors_aux
t __do_global_dtors_aux
080484f0 R __dso_handle
w __gmon_start__
0804849a T __i686.get_pc_thunk.bx
d __init_array_end
d __init_array_start
T __libc_csu_fini
T __libc_csu_init
U __libc_start_main@@GLIBC_2.
A _edata
0804969c A _end
080484cc T _fini
080484e8 R _fp_hw
T _init
T _start
080483c4 T add
b completed.
W data_start
b dtor_idx.
080483a0 t frame_dummy
080483df T main
U printf@@GLIBC_2.
---------------------------------------------------------------------------
[root@monitor ~]# vi test.c int add(int , int);
int add(int a,int b)
{
return a+b;
} int main()
{ int r;
r=add(,);
return ;
} [root@monitor ~]# g++ test.c -o test
[root@monitor ~]# nm test
00000000006007a0 d _DYNAMIC
d _GLOBAL_OFFSET_TABLE_
R _IO_stdin_used
w _Jv_RegisterClasses
T _Z3addii
d __CTOR_END__
d __CTOR_LIST__
D __DTOR_END__
d __DTOR_LIST__
r __FRAME_END__
d __JCR_END__
d __JCR_LIST__
A __bss_start
D __data_start
t __do_global_ctors_aux
00000000004004c0 t __do_global_dtors_aux
R __dso_handle
w __gmon_start__
U __gxx_personality_v0@@CXXABI_1.
d __init_array_end
d __init_array_start
T __libc_csu_fini
00000000004005a0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
A _edata
00000000006009a8 A _end
T _fini
T _init
T _start
000000000040049c t call_gmon_start
b completed.
W data_start
00000000006009a0 b dtor_idx.
t frame_dummy
T main -------------------------------------------------------- . far near huge 指针 (windows)
near
far
huge 综合 .虚拟内存
.一个程序不能访问另一个程序指向的空间
.每个程序的开始地址0x80084000
.程序使用的地址不是物理,而不能逻辑地址
.辑辑编号是 使用 int 4字节整型地址
(,)
每个程序提代了4G的访问能力
. 针对进程的 ( 虚拟内存<---->物理内存)
这样进程有逻辑上的地址空间,屏蔽了真实内内存使用状况,由MMU后台管理映射
进程只操作虚拟地址,禁止访问物理地址,有助于系统稳定 .逻辑地址与物理地址关联
有映射才可访问,如果访问没有映射地址,出现段错误
.虚拟地址在映射的时候有个映射单位 4K(16进制的1000,称为内存页)
EG:malloc(),只少分配4K的内存页,
段错误:无效访问
合法访问:比如malloc分配的空间之外的空间访问,不会出现段错误,但不是合法访问,
可能修改了其他变量值 .虚拟内存的分配
stack:编绎器自动生成代码维护
heap:地址是否映射,映射的空间是否被管理 .brk/sbrk 内存映射函数 man 节 关键字
-8节
:linux shell命令 ls
:系统函数 brk
.标准C文档 fopen
.系统的编程帮助
man tcp
man icmp
man udp
man socket 分配空间,释放空间:
int brk(void *end);分配空间,释放空间
void *sbrk(int size);返回空间地址 应用:
1使用sbrk他配空间
2使用sbrk得到没有映射的虚拟地址
3使用brk他配空间
4使用brk释放空间 sbrk(int size) sbrk与brk后台系统维护一个指针。
指针默认是null
调用sbrk,断定指针是否是0,
如果是0,返回大块空闲空间的首地址并初始化指针,同时把后台指针+size
如果不是0,返回指针,并且把指针位置+SIZE ---------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h> main()
{ int *p1=sbrk();
int *p2=sbrk();
int *p3=sbrk();
int *p4=sbrk();
int *p5=sbrk();
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();
} [root@monitor ~]# gcc test.c -m32 -o test
[root@monitor ~]# ./test
0x9e03000
0x9e03004
0x9e03008
0x9e0300c
0x9e03010 //分配是有序的 4个字节 [root@monitor ]# cd /proc/
[root@monitor ]# cat maps
-002e5000 r-xp ca: /lib/libc-2.12.so
002e5000-002e6000 ---p ca: /lib/libc-2.12.so
002e6000-002e8000 r--p ca: /lib/libc-2.12.so
002e8000-002e9000 rw-p ca: /lib/libc-2.12.so
002e9000-002ec000 rw-p :
00ba3000-00bc1000 r-xp ca: /lib/ld-2.12.so
00bc1000-00bc2000 r--p 0001d000 ca: /lib/ld-2.12.so
00bc2000-00bc3000 rw-p 0001e000 ca: /lib/ld-2.12.so
00cd7000-00cd8000 r-xp : [vdso]
- r-xp ca: /root/test
-0804a000 rw-p ca: /root/test 09e03000-09e04000 rw-p : [heap]
f775a000-f775b000 rw-p :
f7762000-f7764000 rw-p :
ff9c0000-ff9d5000 rw-p : [stack] ------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h> main()
{ int *p1=sbrk();返回没有映射地址,因为0没有分配空间,即逻辑到物理关联没有建立
int *p1=sbrk();//返回空闲首地址(位于段) 4K页倍数 系统分配单元,并修改后台指针为+SIZE
int *(p1+);正常,但不合法
int *(p1+);段错误 } -------------------------------------------------------------------------------
后台维护一个后台变量。初值为NULL #include <stdio.h>
#include <stdlib.h> main()
{ int *p1=sbrk(); //页首地址 (0-3)
int *p2=sbrk(); //(4,199)
int *p3=sbrk(); //(200)
printf("%p\n",p1);
pirntf("%p\n",p2);
printf("%p\n",p3);
printf("%d",getpid());
while(); } [root@monitor ~]# ./test
0x9b63000
0x9b63004
0x9b630cc += [root@monitor ]# cat maps
00ba3000-00bc1000 r-xp ca: /lib/ld-2.12.so
00bc1000-00bc2000 r--p 0001d000 ca: /lib/ld-2.12.so
00bc2000-00bc3000 rw-p 0001e000 ca: /lib/ld-2.12.so
00bc5000-00d55000 r-xp ca: /lib/libc-2.12.so
00d55000-00d56000 ---p ca: /lib/libc-2.12.so
00d56000-00d58000 r--p ca: /lib/libc-2.12.so
00d58000-00d59000 rw-p ca: /lib/libc-2.12.so
00d59000-00d5c000 rw-p :
00d7c000-00d7d000 r-xp : [vdso]
- r-xp ca: /root/test
-0804a000 rw-p ca: /root/test 09b63000-09b64000 rw-p : [heap]
f7706000-f7707000 rw-p :
f770e000-f7710000 rw-p : ff9d7000-ff9ec000 rw-p : [stack] -------------------------------------------------------------------------------------------
释放空间:SIZE为负,释放空间 #include <stdio.h>
#include <stdlib.h> main(){
int *p1=sbrk();
int *p2=sbrk();
int *p3=sbrk(-);
int *p4=sbrk(-);
int *p5=sbrk(-);
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 ------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h> main()
{
//brk绝对移动
int *p=sbrk();
brk(p+); // P+1是地址 后台地址
*p=; brk(p); 移动到P处, 后台地址
*p=; //Segmentation fault } [root@monitor ~]# ./test
Segmentation fault ----------------------------------------
#include <stdio.h>
#include <stdlib.h>
main()
{ int *a=malloc();
*a=;
printf("%p\n",a);
while(); } [root@monitor ~]# ./test
0x209f010 #include <stdio.h>
#include <stdlib.h>
main()
{ int *a=(int *)0x209f010;
*a=;
printf("%d\n",*a);
while(); } [root@monitor ~]# ./test
0x1cce010
------------------------------------- [root@monitor ~]# man brk
BRK() Linux Programmer’s Manual BRK() NAME
brk, sbrk - change data segment size SYNOPSIS
#include <unistd.h> int brk(void *addr); // void *sbrk(intptr_t increment); Feature Test Macro Requirements for glibc (see feature_test_macros()): brk(), sbrk(): _BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE >= DESCRIPTION
brk() and sbrk() change the location of the program break, which defines the end of the process’s data seg-
ment (i.e., the program break is the first location after the end of the uninitialized data segment).
Increasing the program break has the effect of allocating memory to the process; decreasing the break deallo-
cates memory. brk() sets the end of the data segment to the value specified by addr, when that value is reasonable, the
system has enough memory, and the process does not exceed its maximum data size (see setrlimit()). sbrk() increments the program’s data space by increment bytes. Calling sbrk() with an increment of can be
used to find the current location of the program break. RETURN VALUE
On success, brk() returns zero. On error, - is returned, and errno is set to ENOMEM. (But see Linux Notes
below.) On success, sbrk() returns the previous program break. (If the break was increased, then this value is a
pointer to the start of the newly allocated memory). On error, (void *) - is returned, and errno is set to
ENOMEM. . #include <stdio.h>
#include <unistd.h>
main()
{ int *p=sbrk(); //分配4个字节的整数空间
*p=;
printf("%d\n",*p);
} [root@monitor ~]# ./test . #include <stdio.h>
#include <unistd.h>
main()
{ int *p=sbrk();
*p=;
} .
#include <stdio.h>
#include <unistd.h>
main()
{
int *p=sbrk(); //返回没有映射的空间首地址
brk(p+); // P+1分配空间
*p=; //赋值
brk(p); //
*p=; } ------------------------------------------------------------------------------- http://blog.csdn.net/sgbfblog/article/details/7772153
http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/ int brk(void *addr); //后台指针移动
void *sbrk(intptr_t increment); // 后台一个地址值+increment
brk() 这个函数的参数是一个地址,假如你已经知道了堆的起始地址,还有堆的大小,
那么你就可以据此修改 brk() 中的地址参数已达到调整堆的目的。
实际上,在应用程序中,基本不直接使用这两个函数,取而代之的是 malloc() 一类函数,这一类库函数的执行效率会更高。
还需要注意一点,当使用 malloc() 分配过大的空间,比如超出 0x20ff8 这个常数(在我的系统(Fedora15)上是这样,
别的系统可能会有变)时,malloc 不再从堆中分配空间,而是使用 mmap() 这个系统调用从映射区寻找可用的内存空间 #include <stdio.h>
#include <unistd.h>
int main()
{
/*分配10个字节的空间,返回该空间的首地址*/
void* p = sbrk();
void* p2 = sbrk();
void* p3 = sbrk();
void* p4 = sbrk();
printf("p=%p\n", p);
printf("p2=%p\n", p2);
printf("p3=%p\n", p3);
printf("p4=%p\n", p4);
/*用参数为0来获取未分配空间的开始位置*/
void* p0 = sbrk();
printf("p0=%p\n", p0);
void* p5 = sbrk(-);
printf("p5=%p\n", p5);
printf("pid=%d\n", getpid());
sleep();
/*当释放到一个页面的开始位置时,整个页面会被操作系统回收*/
sbrk(-);
while();
}
[root@monitor ~]# gcc test1.c -m32 -o test
[root@monitor ~]# ./test
p=0x8e2c000
p2=0x8e2c00c
p3=0x8e2c010
p4=0x8e2c014
p0=0x8e2c018
p5=0x8e2c018
pid= http://blog.csdn.net/sgbfblog/article/details/7772153
http://www.cnblogs.com/runnyu/tag/apue/
http://bbs.chinaunix.net/thread-4066412-1-1.html 内存分配: 智能指针
stl
malloc:
new
brk/sbrk:结构简单,数据量大 异常处理:
int brk(void *)
void * sbrk()
如果成功brk返加0,sbrk返加指针
失败brk返回-, sbrk返回 (void *)- #include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
extern int errno; //3种 int main()
{ void *p=sbrk(*);
if(p==(void*)-)
{ printf("err!\n");
perror("hello!"); //1种
printf("%m\n"); //2种
printf("::%s\n",strerror(errno)); //3种 } } string:string.h cstring
mem: malloc memset memcmp memcpy bzero
error:
io:
time:
cast :

[root@monitor ~]# vi test.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
Segmentation fault

 

C 高级编程 2 内存管理的更多相关文章

  1. 《Objective-C高级编程》の内存管理の学习笔记

    此日志用于记录下学习过程中碰到的问题 转载请注明出处: http://www.cnblogs.com/xdxer/p/4069650.html <Objective-C高级编程> 人民邮电 ...

  2. 高手写的“iOS 的多核编程和内存管理”

    原文地址:http://anxonli.iteye.com/blog/1097777 多核运算 在iOS中concurrency编程的框架就是GCD(Grand Central Dispatch), ...

  3. C/C++编程之内存管理

    内存分配方式 内存分配方式一共有三种: (1)从静态存储区域分配: 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如,全局变量,静态变量. (2)在栈上创建: 在执行函数时, ...

  4. C#高级编程9 第14章 内存管理和指针

    C#高级编程9 内存管理和指针 后台内存管理 1) 值数据类型 在处理器的虚拟内存中有一个区域,称为栈,栈存储变量的浅副本数据,通过进入变量的作用域划分区域,通过离开变量的作用域释放. 栈的指针指向栈 ...

  5. JNI中的内存管理(转)

    源:JNI中的内存管理 JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互 ...

  6. iPhone之IOS5内存管理(ARC技术概述)

    ARC(Automatic Reference Counting )技术概述 此文章由Tom翻译,首发于csdn的blog,任何人都可以转发,但是请保留原始链接和翻译者得名字.多谢! Automati ...

  7. Objective-C 高级编程:iOS与OS X多线程和内存管理

    <Objective-C 高级编程:iOS与OS X多线程和内存管理> 基本信息 原书名: Pro Multithreading and Memory Management for iOS ...

  8. Objective-C 内存管理与高级环境编程 阅读分享

    常用的调试私有API uintptr_t objc_rootRetainCount(id obj) _objc_autoreleasePoolPrint();//查看自动释放池中的对象 LLVM cl ...

  9. 《C#高级编程》学习笔记----c#内存管理--栈VS堆

    本文转载自Netprawn,原文英文版地址 尽管在.net framework中我们不太需要关注内存管理和垃圾回收这方面的问题,但是出于提高我们应用程序性能的目的,在我们的脑子里还是需要有这方面的意识 ...

随机推荐

  1. HDU 3333-Turing Tree(BIT好题)

    题意: 给你n个数的序列a,q个询问,每个询问给l,r,求在下标i在[l,r]的区间内不含重复数的和 分析: 这类题目觉得很好,很练思维,觉得不太好做. 用BIT维护和,我们可以从前向后扫一遍序列,当 ...

  2. web安全测试&渗透测试之sql注入~~

    渗透测试概念: 详见百度百科 http://baike.baidu.com/link?url=T3avJhH3_MunEIk9fPzEX5hcSv2IqQlhAfokBzAG4M1CztQrSbwsR ...

  3. 《Python 学习手册4th》 第九章 元组、文件及其他

    ''' 时间: 9月5日 - 9月30日 要求: 1. 书本内容总结归纳,整理在博客园笔记上传 2. 完成所有课后习题 注:“#” 后加的是备注内容 (每天看42页内容,可以保证月底看完此书) “重点 ...

  4. Python字典增删操作技巧简述

    Python编程语言是一款比较容易学习的计算机通用型语言.对于初学者来说,首先需要掌握的就是其中的一些基础应用.比如今天我们为大家介绍的Python字典的相关操作,就是我们在学习过程中需要熟练掌握的技 ...

  5. Selenium2Library系列 keywords 之 _SelectElementKeywords 之 list_should_have_no_selections(self, locator)

    def list_should_have_no_selections(self, locator): """Verifies select list identified ...

  6. JDBC获取表的主键

    JDBC获取表的主键 案例,创建订单,并根据订单号向订单明细表插入数据 sql语句: 创建两表 create table orders(  id number(4) primary key,  cus ...

  7. 用Vmware安装centos5

    Vmware安装过程就不详述了,这里从创建虚拟机开始记录. 选择创建虚拟机 下一步 选择稍后安装 选择安装的操作系统版本,需要说明的是,CentOs 5 就是RHEL 5 设置虚拟机名称及虚拟机位置 ...

  8. 去除下载电影和电视剧文件名中的多余字符[python实现]

    讨厌下载电影和电视剧文件名中的多余字符(如网址和广告字样),,搞得文件名好长,可以使用下面的Python代码,自行修改即可. #!\usr\bin\env python # -*- coding: u ...

  9. codeforce 702D Road to Post Office 物理计算路程题

    http://codeforces.com/contest/702 题意:人到邮局去,距离d,汽车在出故障前能跑k,汽车1公里耗时a,人每公里耗时b,修理汽车时间t,问到达终点最短时间 思路:计算车和 ...

  10. HDU 1536 sg-NIM博弈类

    题意:每次可以选择n种操作,玩m次,问谁必胜.c堆,每堆数量告诉. 题意:sg—NIM系列博弈模板题 把每堆看成一个点,求该点的sg值,异或每堆sg值. 将多维转化成一维,性质与原始NIM博弈一样. ...