date 2020.07.08
环境变量
1.访问环境变量表
#include<stdlib.h> //加载库
通过env命令可以查看当前shell进程的环境变量
子进程在默认环境下继承其父进程的环境变量
2.访问特定环境
#include<stdlib.h> //加载库
a.char* getenv(char const* name); 根据环境变量名称获取该变量的值
成功返回与参数匹配的环境变量的值,失败返回NULL;
name :环境变量名
b.int putenv(char* string); 增加新的环境变量或修改已有环境变量的值;
成功返回0;失败返回非0;
string:形如“变量名 = 变量值”形式的字符串。(变量名存在为修改变量值,不存在为新增变量值)
int setenv(char const* name,char *const value ,int overwrite);
name :环境变量名
value:环境变量值
overwrite:当所给环境变量名已存在时(存在为1;反之为0)是否覆盖原值;
c. int unsetenv(char const* name); 删除环境变量;
成功返回0;失败返回-1。
name :环境变量名
int clearenv(void); 清除所有环境变量,同时将environ置NULL。
成功返回0;失败返回非0。
示例代码
/*
date 2020-07-07
version 1.0
name 环境变量操作演示
*/
#include<stdio.h>
void penv(char* ppc) {
printf("---------环境变量----\n");
while(ppc && *ppc)
printf("%s\n",*ppc++);
printf("---------------------\n");
}
int main(int argc ,char* argv[] ,char* env[]) {
extern char** environ;
penv(environ);
penv(env);
printf("%p%p\n",environ ,env);
printf("%s\n",getenv("PATH"));
putenv("STUDENT=MYNAME");
penv(environ);
putenv("STUDENT=YOURNAME");
penv(environ);
setenv("CITY","Chengdu",0);
penv(environ);
setenv("CITY","Sanya",0);
penv(environ);
setenv("CITY","Sanya",1);
penv(environ);
unsetenv("CITY");
penv("environ");
clearenv();
penv(environ);
printf("%p\n",environ);
return 0;
}
内存管理:内存分配与释放
1.内存分配和释放方式
a. void foo(void) {
int a; // 自动分配,自动释放
.....
}
b. void bar(void){
int *b = (int*)malloc(sizeof(int)); //手动分配,动态释放
...
free(b)
}
2.应用程序: 业务逻辑对内存资源的使用
STL:代表不同数据结构标准容器
C++:new/delete
C:malloc/calloc/realloc/free
POSIX:sbrk/brk
系统内核:mmap/munmap
系统底层:kalloc/vmalloc
硬件驱动:get_free_page
硬件设备:硬件指令集
虚拟内存
1.虚拟内存
虚拟内存的本质就是一个地址范围,用于在应用程序中访问储存空间,但实际存放的数据是物理内存,物理内存和虚拟内存之间存在动态的对应关系,称之为内存映射。
32机器的地址范围:0 ~ 4G-1
内存壁垒
每个进程的地址空间可被划分为内核空间和用户空间两部分,其中内核空间共享同一个物理内存区域,而用户空间映射到不同的物理内存区域,这就是进程间的内存壁垒。
2.段错误
SIGSEGV(11)
试图访问没有映射到物理内存的虚拟内存
试图已以非法方式访问虚拟内存,如对只读内存写操作
/*
date 2020-07-09
name 段错误操作演示
version 1.0*/
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int* p = malloc(sizeof(int));
printf("%p\n",p);
*p = 1234;
printf("%p\n",*p);
free(p);
}
a.以相对方式分配和释放虚拟内存
#include<unistd.h>
void* sbrk(intptr_t increment);
成功返回调用该函数前的堆尾指针,失败返回-1.
increment:堆内存的字节增量(> 0 分配内存; < 0 释放内存; = 0 当前堆尾)
堆尾指针
堆空间最后一个被分配字节的下一个字节的地址
示例代码
/*
date 2020-07-09
name sbrk操作演示;
version 1.0
*/
#include<stdio.h>
#include<unistd.h>
int main(void) {
int* p1 = sbrk(sizeof(int));
*p1 = 123;
double* p2 = sbrk(sizeof(double));
*p2 = 4.56;
char* p3 = sbrk(sizeof(char) * 256);
sprintf(p3,"Hello ,World");
printf("%d %g %s\n,*p1,*p2,p3");
return 0;
}
b.以绝对方式分配和释放虚拟内存
int brk(void* end_data_segment)
成功返回0 ,失败返回-1
end_data_segment 堆尾指针的目标位置(> 堆尾指针的目标位置 分配内存 ;< 堆尾指针的目标位置 释放内存 ;= 堆尾指针的目标位置 空操作)
示例代码
/*
date 2020-07-09
name brk操作演示
version 1.0
*/
#include<stdio.h>
#include<unistd.h>
int main(void) {
setbuf(stdout NULL);
printf("%p\n",sbrk(0));
int* p1 = sbrk(sizeof(int));
*p1 = 123;
double* p2 = sbrk(sizeof(double));
*p2 = 4.56;
char *p3 = sbrk(sizeof(char) * 256);
sprintf(p3 ,"Helle ,World");
printf("%d %g %s\n",*p1 ,*p2,p3);
//sbrk(-(sizeof)(int) + sizeof(doyuble) + sizeof((char) * 256));
brk(p1);
printf("%p\n",sbrk(0));
return 0;
}
c.用sbrk 分配内存 ,用brk释放内存;
3.mmap 和 munmap 函数
a.建立虚拟内存到物理内存或磁盘文件的映射
#include<sys/mman.h>
void* mmap(void * start ,size_t length,int prot ,int flags,int fd ,off_t offset);
成功返回映射区虚拟内存的起始地址,失败返回MAP_FAILED(-1).
start :映射区虚拟内存的起始地址,NULL系统自动选定后返回;
length:映射区字节数,自动按页圆整;
port:映射区操作权限(PROT_READ 读 PROT_WRITE 写 PORT_EXEC 执行 PORT_NONE 不可访问);
flags: 映射标志
MAP_ANONYMOUS | MAP_PRIVATE 虚拟内存到物理内存的映射;
MAP_SHARED 虚拟内存到磁盘文件的映射;
fd:文件描述符;
offset:文件偏移量 ,自动按页对齐。
b.解除虚拟内存到物理内存或磁盘文件的映射
#include<sys/mman.h>
void* munmap(void * start ,size_t length);
start :映射区虚拟内存的起始地址,
length:映射区字节数,自动按页圆整;
示例代码
/*
date 2020-07-09
name manmap操作演示
version 1.0
*/
int main(void) {
char* p = mmap(NULL,8192,PORT_READ | PORT_WRITE,MAP_ANONTMOUS | MAP——PRIVATE,0,0);
if(P1 == MAP_FAILED) {
perror)("mmap");
return -1;
}
strcpy(p1,"第一个内存页");
print("%p\n",p1);
if(munmap(p1,4096) == -1) {
perror)("mmap");
return -1
}
printf("%s\n",p1);
char* p2 = p1 + 4096;
strcpy(p1,"第二个内存页");
print("%p\n",p1);
if(munmap(p1,4096) == -1) {
perror)("mmap");
return -1
}
//printf("%s\n",p2);
return 0;
}
系统调用
应用程序的层次结构