C 高级编程 2 内存管理
理解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 内存管理的更多相关文章
- 《Objective-C高级编程》の内存管理の学习笔记
此日志用于记录下学习过程中碰到的问题 转载请注明出处: http://www.cnblogs.com/xdxer/p/4069650.html <Objective-C高级编程> 人民邮电 ...
- 高手写的“iOS 的多核编程和内存管理”
原文地址:http://anxonli.iteye.com/blog/1097777 多核运算 在iOS中concurrency编程的框架就是GCD(Grand Central Dispatch), ...
- C/C++编程之内存管理
内存分配方式 内存分配方式一共有三种: (1)从静态存储区域分配: 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如,全局变量,静态变量. (2)在栈上创建: 在执行函数时, ...
- C#高级编程9 第14章 内存管理和指针
C#高级编程9 内存管理和指针 后台内存管理 1) 值数据类型 在处理器的虚拟内存中有一个区域,称为栈,栈存储变量的浅副本数据,通过进入变量的作用域划分区域,通过离开变量的作用域释放. 栈的指针指向栈 ...
- JNI中的内存管理(转)
源:JNI中的内存管理 JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互 ...
- iPhone之IOS5内存管理(ARC技术概述)
ARC(Automatic Reference Counting )技术概述 此文章由Tom翻译,首发于csdn的blog,任何人都可以转发,但是请保留原始链接和翻译者得名字.多谢! Automati ...
- Objective-C 高级编程:iOS与OS X多线程和内存管理
<Objective-C 高级编程:iOS与OS X多线程和内存管理> 基本信息 原书名: Pro Multithreading and Memory Management for iOS ...
- Objective-C 内存管理与高级环境编程 阅读分享
常用的调试私有API uintptr_t objc_rootRetainCount(id obj) _objc_autoreleasePoolPrint();//查看自动释放池中的对象 LLVM cl ...
- 《C#高级编程》学习笔记----c#内存管理--栈VS堆
本文转载自Netprawn,原文英文版地址 尽管在.net framework中我们不太需要关注内存管理和垃圾回收这方面的问题,但是出于提高我们应用程序性能的目的,在我们的脑子里还是需要有这方面的意识 ...
随机推荐
- 【LeetCode 160】Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...
- SQL Server2005安装配置以及测试
SQL Server2005有2种版本,一种是集成版的, 一种是2个文件夹形式的.这里使用后者,安装文件夹名字为:SQL Server x86,该文件夹里面有Servers和Tools文件夹以及一些其 ...
- STM32F407 外扩SRAM
字节控制功能.支持高/低字节控制. 看看实现 IS62WV51216 的访问,需要对 FSMC进行哪些配置. 这里就做一个概括性的讲解.步骤如下: 1)使能 FSMC 时钟,并配置 FSMC 相关的 ...
- flex 图片旋转(解决公转和自转问题)
在Flex中图片的旋转是既有公转和自转的.这样在图片旋转的时候就有一定小麻烦: 为了更好地说明问题,先引入两个概念:“自转”和“公转”.想象一下,地球在绕着太阳公转的同时,它自己也在自转.Flash应 ...
- html 5新特性 --用SVG绘制的微信logo
一个简单的SVG绘制图片的小案例. 效果图: 代码如下: <style> * { ; ; } body { background-color: #d5d3d4; } .container ...
- 【转】MySql数据库--mysql_real_escape_string()函数
MySql数据库--mysql_real_escape_string()函数 unsigned long mysql_real_escape_string(MYSQL *mysql, char *to ...
- 【Hadoop代码笔记】Hadoop作业提交之Child启动reduce任务
一.概要描述 在上篇博文描述了TaskTracker启动一个独立的java进程来执行Map任务.接上上篇文章,TaskRunner线程执行中,会构造一个java –D** Child address ...
- redis高级实用特性
1. 安全性 2. 主从复制 3. 事务处理 4. 持久化机制 5. 发布订阅消息 : 可以做一个消息系统 6. 虚拟内存的使用 一 . 安全性 设置客户端连接后进行任何其他指定前需要使用的密码 . ...
- Android 用MediaCodec实现视频硬解码(转)
本文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码.例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示.我将尽量讲得简短而清晰,不展示 那些不相 ...
- POJ3237-Tree (树链剖分,线段树区间更新+点更新+区间查询)
两个更新操作,一个将第i条路径权值改为w,一个是将a-b之间所有路径权值取反. 一个查询操作,求a-b之间路径中权值最大的边. 很容易想到维护一个最大最小值,取反就是把最大最小取反交换一下. 开始遇到 ...