uc_day03
来源:互联网 发布:网络电视外置无线网卡 编辑:程序博客网 时间:2024/06/05 10:21
一,虚拟内存管理技术
1,Linux操作系统采用虚拟内存管理技术
真正的物理地址是接触不到的,真正的物理地址只有操作系统才能
我们平时所说的地址是虚拟地址,也称为逻辑地址
2,段错误问题
A,对内存空间的操作超出权限的限制,会导致段错误
比如:写只读空间
B,访问没有对应物理空间的虚拟地址,会导致段错误
3,堆空间分配
malloc 会在后台维护一个双向链表的数据结构,并且每次malloc
会在结束位置有标记(12Byte),越界访问会破坏标记,从而导致内存释放出现问题。
总之,使用malloc时不要越界访问。
二,内存页面管理
page.c
#include<stdio.h>
#include<stdlib.h>
int main(){
int* p = malloc(4);
*p = 100;
*(p+100) = 100;
return 0;
}
操作系统分配物理内存空间时,会按页为单位进行分配。一般系统
一页为4096Bytes。操作系统分配好物理空间后,会给进程分配虚拟内存地址
与物理空间一一对应起来,这个叫内存映射。
对于malloc来说,操作系统第一次会直接分配33个页面的物理内存空间并映射
malloc分小内存和大内存分配
三,brk/sbrk的虚拟内存管理----UNIX内存分配函数
sbrk仅仅记录当前的位置,一个一个页面的分配的。维护的后台位置是os在
void* sbrk(int size)
-size=0 返回sbrk/brk上次的末尾地址
-size>0 分配内存空间,返回上一次末尾地址
-size<0 释放空间
#include<unistd.h>
sbrk.c
#include<stdio.h>
#include<unistd.h>
int main(){
void* p1 = sbrk(4);//分配四个字节的空间
void* p2 = sbrk(4);//页面不会再分配
void* p3 = sbrk(4);
sbrk(-4);//释放4个字节
void* cur = sbrk(0);//返回当前位置
return 0;
}
ps aux
----------------------------------------------------------------
int brk(void* end_data_segment);
成功:返回0
失败:-1
#include<stdio.h>
#include<unistd.h>
int main(){
void* p = sbrk(0);//获取当前位置
printf("p=p%\n",p);
brk(p+4);//分配了4个字节的空间
brk(p+8);//又分配了4Bytes
brk(p+4);//释放4Bytes
char* str = sbrk(0);
brk(str+10);
strcpy(str,"abcdefg");
brk(p);//释放所有的空间
/*
brk(p+14);
strcpy(p+4,"abcdefg");
char* str = p+4;
*/
}
一般情况下,我们使用sbrk分配空间,brk释放空间
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main(){
void* p = sbrk(4);
int* pi = p;
*pi = 100;
//放一个doulbe
double* pd = sbrk(sizeof(double)):
*pd = 3.14;
//放一个字符串hello
char* str = sbrk(10);
strcpy(str,"hello");
brk(p);//释放所有空间
return 0;
}
四,mmap函数-----内存映射函数,只做内存映射
#include<sys/mman.h>
void *mmap(void *start,size_t length,int prot,int flags,
int fd,off_t offset);
*start:开始映射的虚拟内存空间
prot:权限
flags:标记
fd:文件描述符
offset:映射文件偏移量
返回值是映射好的首地址
mmap.c
#include<stdio.h>
#include<sys/mman.h>
int main(){
//映射一片内存空间
void* p = mmap(
sbrk(0)或者0,//映射好的空间的首地址(虚拟地址),0为放弃指定地址的权利,让操作系统找
4,//映射空间的大小,按页面映射,故按页面对齐(不够一页则补齐)
PROT_READ | PROT_WRITE,//代码区内存空间一般需要执行权限
MAP_SHARED | MAP_ANONYMOUS,//MAP_PRIVATED与MAP_SHARED必须选其一,映射到内存哪个都无所谓,如果映射到文件需要选择
//MAP_ANONYMOUS意味着映射到物理内存,没有这个选项,意味着映射到文件,文件可以当内存,指针指来指去
0,//文件描述符
0//文件偏移量
);
//if(p == (void*)-1)
if(p == MAP_FAILED){
perror("内存映射失败");
return -1;
}
munmap(p,4);//结束映射
return 0;
}
五,系统调用
硬件
||
Kernel:内核,是大量驱动程序,系统功能程序....
||
系统调用:内核给外界公开的访问接口,本质上是一些函数
函数调用时进程进入系统态
六,文件
1,特殊文件
/dev/null 空设备文件 代表不存在的文件 Unix黑洞
cat /dev/null > a.txt//清空a.txt
find / -name perl 2>/dev/null
/dev/tty 输入输出设备
2,文件描述符
值为一个非负整数
用于表示一个打开文件
1-标准输出
2-错误输出
0-标准输入
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
-----------------------------------------------------------
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
//创建三个参数,非创建两个参数
int main(){
int fd = open("a.txt",O_RDWR|O_CREAT,0666);
if(fd == -1){
perror("创建文件失败");
exit(-1);
}
printf("文件创建成功\n");
int fd2 = open("a.txt",O_RDONLY);
if(fd2 == -1){
perror("打开文件失败");
exit(-1);
}
printf("打开文件成功\n");
return 0;
}
创建出来的文件权限是644,屏蔽了本组和其他人写的权限
umask 022
3,open函数
int 文件描述符 = open(文件名,int flags);
flags:
O_RDONLY
O_WRONLY
O_RDWR
O_CREAT:创建文件,必须有第三个参数(权限)
O_EXCL:和O_CREAT一起,如果创建的文件已经存在,返回-1
O_TRUNC:和O-CREAT一起使用,如果创建的文件已经存在,删除此文件,创建新的文件
3,write函数
man -s2 write
ssize_t write(int fd,const void *buf,size_t count);
#include<stdio.h>
#include<unistd.h>
#include<fcnl.h>
#include<stdlib.h>
#include<string.h>
int main(){
int fd =
open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0666);
if(fd == -1) perror("文件创建失败"),exit(-1);
int res = write(fd,"Hello World!",strlen("Hello World!"));
if(res == -1){
perror("写文件失败");
exit(-1);
}
printf("成功地向文件写了%d字节的数据",res);
write(1,"Hello world!\n",13);//显示在了显示器上了
return 0;
}
3,read函数
ssize_t read(int fd,void* buf,size_t count);
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
int fd = open("a.txt",O_RDONLY);
if(fd == -1){
perror("打开文件失败");
exit(-1);
}
char buf[100] = {};
int res = read(fd,buf,sizeof(buf));
if(res == -1){
perror("读取文件失败");
exit(-1);
}
printf("从文件中读到%d字节的数据\n",res);
printf("内容:%s\n",buf);
return 0;
}
1,Linux操作系统采用虚拟内存管理技术
真正的物理地址是接触不到的,真正的物理地址只有操作系统才能
我们平时所说的地址是虚拟地址,也称为逻辑地址
2,段错误问题
A,对内存空间的操作超出权限的限制,会导致段错误
比如:写只读空间
B,访问没有对应物理空间的虚拟地址,会导致段错误
3,堆空间分配
malloc 会在后台维护一个双向链表的数据结构,并且每次malloc
会在结束位置有标记(12Byte),越界访问会破坏标记,从而导致内存释放出现问题。
总之,使用malloc时不要越界访问。
二,内存页面管理
page.c
#include<stdio.h>
#include<stdlib.h>
int main(){
int* p = malloc(4);
*p = 100;
*(p+100) = 100;
return 0;
}
操作系统分配物理内存空间时,会按页为单位进行分配。一般系统
一页为4096Bytes。操作系统分配好物理空间后,会给进程分配虚拟内存地址
与物理空间一一对应起来,这个叫内存映射。
对于malloc来说,操作系统第一次会直接分配33个页面的物理内存空间并映射
malloc分小内存和大内存分配
三,brk/sbrk的虚拟内存管理----UNIX内存分配函数
sbrk仅仅记录当前的位置,一个一个页面的分配的。维护的后台位置是os在
void* sbrk(int size)
-size=0 返回sbrk/brk上次的末尾地址
-size>0 分配内存空间,返回上一次末尾地址
-size<0 释放空间
#include<unistd.h>
sbrk.c
#include<stdio.h>
#include<unistd.h>
int main(){
void* p1 = sbrk(4);//分配四个字节的空间
void* p2 = sbrk(4);//页面不会再分配
void* p3 = sbrk(4);
sbrk(-4);//释放4个字节
void* cur = sbrk(0);//返回当前位置
return 0;
}
ps aux
----------------------------------------------------------------
int brk(void* end_data_segment);
成功:返回0
失败:-1
#include<stdio.h>
#include<unistd.h>
int main(){
void* p = sbrk(0);//获取当前位置
printf("p=p%\n",p);
brk(p+4);//分配了4个字节的空间
brk(p+8);//又分配了4Bytes
brk(p+4);//释放4Bytes
char* str = sbrk(0);
brk(str+10);
strcpy(str,"abcdefg");
brk(p);//释放所有的空间
/*
brk(p+14);
strcpy(p+4,"abcdefg");
char* str = p+4;
*/
}
一般情况下,我们使用sbrk分配空间,brk释放空间
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main(){
void* p = sbrk(4);
int* pi = p;
*pi = 100;
//放一个doulbe
double* pd = sbrk(sizeof(double)):
*pd = 3.14;
//放一个字符串hello
char* str = sbrk(10);
strcpy(str,"hello");
brk(p);//释放所有空间
return 0;
}
四,mmap函数-----内存映射函数,只做内存映射
#include<sys/mman.h>
void *mmap(void *start,size_t length,int prot,int flags,
int fd,off_t offset);
*start:开始映射的虚拟内存空间
prot:权限
flags:标记
fd:文件描述符
offset:映射文件偏移量
返回值是映射好的首地址
mmap.c
#include<stdio.h>
#include<sys/mman.h>
int main(){
//映射一片内存空间
void* p = mmap(
sbrk(0)或者0,//映射好的空间的首地址(虚拟地址),0为放弃指定地址的权利,让操作系统找
4,//映射空间的大小,按页面映射,故按页面对齐(不够一页则补齐)
PROT_READ | PROT_WRITE,//代码区内存空间一般需要执行权限
MAP_SHARED | MAP_ANONYMOUS,//MAP_PRIVATED与MAP_SHARED必须选其一,映射到内存哪个都无所谓,如果映射到文件需要选择
//MAP_ANONYMOUS意味着映射到物理内存,没有这个选项,意味着映射到文件,文件可以当内存,指针指来指去
0,//文件描述符
0//文件偏移量
);
//if(p == (void*)-1)
if(p == MAP_FAILED){
perror("内存映射失败");
return -1;
}
munmap(p,4);//结束映射
return 0;
}
五,系统调用
硬件
||
Kernel:内核,是大量驱动程序,系统功能程序....
||
系统调用:内核给外界公开的访问接口,本质上是一些函数
函数调用时进程进入系统态
六,文件
1,特殊文件
/dev/null 空设备文件 代表不存在的文件 Unix黑洞
cat /dev/null > a.txt//清空a.txt
find / -name perl 2>/dev/null
/dev/tty 输入输出设备
2,文件描述符
值为一个非负整数
用于表示一个打开文件
1-标准输出
2-错误输出
0-标准输入
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
-----------------------------------------------------------
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
//创建三个参数,非创建两个参数
int main(){
int fd = open("a.txt",O_RDWR|O_CREAT,0666);
if(fd == -1){
perror("创建文件失败");
exit(-1);
}
printf("文件创建成功\n");
int fd2 = open("a.txt",O_RDONLY);
if(fd2 == -1){
perror("打开文件失败");
exit(-1);
}
printf("打开文件成功\n");
return 0;
}
创建出来的文件权限是644,屏蔽了本组和其他人写的权限
umask 022
3,open函数
int 文件描述符 = open(文件名,int flags);
flags:
O_RDONLY
O_WRONLY
O_RDWR
O_CREAT:创建文件,必须有第三个参数(权限)
O_EXCL:和O_CREAT一起,如果创建的文件已经存在,返回-1
O_TRUNC:和O-CREAT一起使用,如果创建的文件已经存在,删除此文件,创建新的文件
3,write函数
man -s2 write
ssize_t write(int fd,const void *buf,size_t count);
#include<stdio.h>
#include<unistd.h>
#include<fcnl.h>
#include<stdlib.h>
#include<string.h>
int main(){
int fd =
open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0666);
if(fd == -1) perror("文件创建失败"),exit(-1);
int res = write(fd,"Hello World!",strlen("Hello World!"));
if(res == -1){
perror("写文件失败");
exit(-1);
}
printf("成功地向文件写了%d字节的数据",res);
write(1,"Hello world!\n",13);//显示在了显示器上了
return 0;
}
3,read函数
ssize_t read(int fd,void* buf,size_t count);
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
int fd = open("a.txt",O_RDONLY);
if(fd == -1){
perror("打开文件失败");
exit(-1);
}
char buf[100] = {};
int res = read(fd,buf,sizeof(buf));
if(res == -1){
perror("读取文件失败");
exit(-1);
}
printf("从文件中读到%d字节的数据\n",res);
printf("内容:%s\n",buf);
return 0;
}
0 0