#include <stdio.h>
#include <unistd.h>
int isPrimer(int a)
{
int i;
for(i=2;i<a;i++)
{
if(a%i==0)
{
return 1;
}
}
return 0;
}
main()
{
int i=2;
int b;
int *r;
int *p;
p=sbrk(0);
r=p;
for(;i<100;i++)
{
b=isPrimer(i);
if(b==0)
{
brk(r+1);//分配一个内存地址
*r=i;
r=sbrk(0);//返回上一个分配地址结束的地方的地址
}
}
i=0;
r=p;
while(r!=sbrk(0))
{
printf("%d\n",*r);
r++;
}
brk(p);//free
}
内存管理
硬件层次
内存结构管理
内核层次
内存映射
堆扩展
语言层次
c:malloc
c++:new
数据结构
STL
智能指针
1.问题:
malloc怎么分配空间?
malloc与new的关系?
2.Linux对内存的结构描述
1./proc/${pid}/ 存放进程运行时候所有的信息(包括内存结构)
结论:
任何程序的内存空间分成4个基本部分
1.代码区
2.全局栈区
3.堆
4.局部栈
进程查看
ps aue
2.理解程序的变量与内存空间的关系
结论:
1.内存分四个区.
2.各种变量对应存放区
3.堆栈是一种管理内存的数据结构.
4.查看程序的内存地址.
3.理解malloc的工作的原理
malloc使用一个数据结构(链表)维护分配空间
链表的构成:分配的空间/上一个空间数据/下一个空间/空间大小等信息.
对malloc分配的空间不要越界访问.因为容易破坏后台维护结构.导致malloc/free/calloc/realloc不正常工作.
4.C++的new与malloc的关系
malloc new new[]
realloc
new()
calloc new[]
free
delete delete[]?
结论:new的实现使用的是malloc来实现的.
区别:new使用malloc后,还要初始化空间.
基本类型,直接初始化成默认值.
UDT类型,调用指定的构造器
delete调用free实现.
delete负责调用析构器.然后在调用free
new与new[]区别
new只调用一个构造器初始化.
new[]循环对每个区域调用构造器.
delete 与delete[]
5.函数调用栈空间的分配与释放
5.1.总结:
1.函数执行的时候有自己的临时栈.
2.函数的参数就在临时栈中.如果函数传递实参.则用来初始化临时参数变量.
3.通过积存器返回值.(使用返回值返回数据)
4.通过参数返回值.(参数必须是指针)
指针指向的区域必须事先分配.
5.如果参数返回指针.参数就是双指针.
5.2.__stdcall __cdecl __fastcall
1.决定函数栈压栈的参数顺序.
2.决定函数栈的清空方式
3.决定了函数的名字转换方式.
6.far near huge指针
near 16
far 32
huge 综合
四.虚拟内存
问题:
一个程序不能访问另外一个程序的地址指向的空间.
理解:
1.每个程序的开始地址0x80084000
2.程序中使用的地址不是物理,而是逻辑地址(虚拟内存).
逻辑地址仅仅是编号.编号使用int 4字节整数表示.
4294967296
每个程序提供了4G的访问能力
问题:
逻辑地址与物理地址关联才有意义:过程称为内存映射.
背景:
虚拟内存的提出:禁止用户直接访问物理存储设备.
有助于系统的稳定.
结论:
虚拟地址与物理地址映射的时候有一个基本单位:
4k 1000 内存页.
段错误:无效访问.
合法访问:比如malloc分配的空间之外的空间可以访问,但访问非法.
虚拟内存的分配.
栈:编译器自动生成代码维护
堆:地址是否映射,映射的空间是否被管理.
1.brk/sbrk 内存映射函数
补充:帮助手册
man 节 关键字
1-8 1:Linux系统(shell)指令
2:系统函数
3:标准C函数
7:系统编程帮助
分配释放内存:
int brk(void *end);//分配空间,释放空间
void *sbrk(int size);//返回空间地址
应用:
1.使用sbrk分配空间
2.使用sbrk得到没有映射的虚拟地址.
3.使用brk分配空间
4.使用brk释放空间
理解:
sbrk(int size)
sbrk与brk后台系统维护一个指针.
指针默认是null.
调用sbrk,判定指针是否是0,是:得到大块空闲空间的首地址初始化指针.
同时把指针+size
否:返回指针,并且把指针位置+size
总结:
智能指针
stl
new
malloc
brk/sbrk
异常处理
int brk(void*)
void *sbrk(int);
如果成功.brk返回0 sbrk返回指针
失败 brk返回-1 sbrk返回(void*)-1
Unix函数错误,修改内部变量:
errno
字符串函数string.h cstring
内存管理函数malloc memset mamcmp memcpy ...
bzero
错误处理函数
标准IO函数
时间函数
类型转换函数
回顾:
brk/sbrk
int brk(void *p);
void *sbrk(int);
维护一个位置。brk/sbrk改变这个位置
brk改变绝对位置。
sbrk相对改变位置。
补充:全新的类型。
永远记住:c的基本类型就:整数(1,2,4),小数(4,8)
unsigned signed
所有全新类型都是使用typedef重新定义。
新的类型的C的原型。
类型重定义的好处:
1.维护方便
2.移植
3.容易理解
映射虚拟内存
没有任何额外维护数据的内存分配。
mmap(分配)/unmap(释放)
1.函数说明
void *mmap(
void *start,//指定映射的虚拟地址 0由系统指定开始位置)
size_t length,//映射空间大小 pagesize倍数
int prot,//映射权限 PROT_NONE | PROT_READ PROT_WRITE PROT_EXEC
int flags,//映射方式
int fd,//文件描述符号
offset_t off);//文件中的映射开始位置(必须是pagesize的倍数)
映射方式:
内存映射:匿名映射。
文件映射:映射到某个文件
只有文件映射最后两个参数有效。
MAP_ANONYMOUS
MAP_SHARED MAP_PRIVATE(二选一)
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
int *p=mmap(
NULL,
getpagesize(),
PROT_READ,
MAP_ANONYMOUS|MAP_SHARED,
0,0);
*p=20;
*(p+1)=30;
*(p+2)=40;
printf("%d\n",p[2]);
munmap(p,4096);
}
2.案例
3.总结
选择什么样的内存管理方法?
智能指针(指针池)
STL
new
malloc (小而多数据)
brk/sbrk (同类型的大块数据,动态移动指针)
mmap/munmap(控制内存访问/使用文件映射/控制内存共享)