zoukankan      html  css  js  c++  java
  • 第6章.md

    进程

    进程号

    getpid()

    pid_t getpid(void)

    ​ Linux内核2.4与其更早版本,进程号上限32767。上限由内核常量PID_MAX定义。Linux2.6之后可更改/proc/sys/kernel/pid_max。内核参数修改:/etc/sysctl.d/99-sysctl.conf --> kernerl.pid_max=65535。64位平台可达到2^22。

    ​ 当进程号满之后,程序计数器将从300开始,而不是1。

    getppid()

    进程内存布局

    • text段: 包含程序指令。只读属性。
    • 初始化数据段:已初始化的全局变量和静态变量
    • 未初始化(BSS)段:程序仅保存BSS段的位置和大小,运行时由程序加载器分配这一空间。
    • stack
    • heap

    此处的段(segment)与硬件分段(segmentation)不同

    ​ 应用程序二进制接口(ABI):规定程序运行时如何与内核或库函数提供的服务交换信息。(个人理解: 不同编译器有不同优化方式,即函数传参不同,寄存器使用不同,ABI保证不同编译器编译出的程序使用相同的库)。

    C获取各段地址

    c语言提供3个全局符号: etext edata end 分别获取本程序text段、bss段、初始化段结尾下一字节地址

    显示声明:

    extern char etext, edata, end;
    

    各内存段在x86-32体系结构中布局:

    img

    虚拟内存管理

    程序仅有部分地址空间存在RAM中。

    虚拟内存的规划之一是将每个程序使用的内存切割成小型的、固定大小的页单元。

    进程尝试访问地址无页表目录对应时,将收到SIGSEGV信号。

    进程页表改变条件

    • 栈向下增长超过之前曾到达的位置
    • 在heap中分配或释放内存时,通过调用brk()、sbrk()、malloc()函数族来提升program break的位置。
    • 调用shamt()连接共享内存
    • 当mmap()创建内存映射时,或者munmap()解除内存映射时。

    img

    栈和栈帧

    栈:内核栈、用户栈

    用户栈信息:

    • 函数实参、局部变量

    • 函数调用信息: PC、寄存器副本

    内核栈信息:

    进程陷入内核态后,先把用户堆栈的地址保存到内核堆栈中,然后设置设置CPU堆栈寄存器为内核栈的地址,这样就完成了用户栈到内核栈的转换。进程由用户栈到内核栈转换时,进程的内核栈总是空的。每次从用户态陷入内核时,得到的内核栈都是空的,所以在进程陷入内核时,直接把内核栈顶地址给堆栈指针寄存器即可。

    命令行参数

    int main(int argc, char *argv[], char *env[])
    {
    	return 0;
    }
    

    Linux的ARG_MAX曾固定为32页面大小。参数存储自己上限通过ARG_MAX限定,通过调用sysconf(__SC_ARG_MAC)确定上限值。

    环境列表

    访问使用全局变量char **environ;

    getenv() 获得环境变量

    char *getenv(const char*name);

    获取环境变量的值。返回的字符串不应修改

    putenv(), setenv() 设置环境变量

    int putenv(char *string);

    string --> “name=value” 字符串不应为自动变量,该字符串将成为环境一部分

    int setenv(const char *name, const char *value, int overwrite);

    setenv()将复制字符串值,overwrite==0时将不会覆盖已存在的环境变量

    (个人感觉比putenv()更好,因为字符串复制了一份)

    unsetenv() clearenv() 移除环境变量

    int unsetenv(const char *name);

    int clearenv(void); 清除所有环境变量

    clearenv()unsetenv()使用可能会导致内存泄漏。clearenv不能获得setenv新分配的字符串地址

    非局部跳转

    setjmp() longjmp()

    #include <setjmp.h>
    int setjmp(jmp_buf env);
        Returns 0 on initial call, nonzero on return via longjmp()
    void longjmp(jmp_buf env, int val);
    

    longjmp()第一次返回setjmp位置,setjmp将返回0

    longjmp()不能返回已释放的函数

    优化编译器问题

    编译器优化将重组程序指令执行。cpu可能并行一段无关程序。

    #include <stdio.h>
    #include <stdlib.h>
    #include <setjmp.h>
    
    static jmp_buf env;
    
    void doJump(int nvar, int rvar, int vvar);
    
    int main(int argc, char *argv[])
    {
    	int nvar;
    	register int rvar;
    	volatile int vvar;
    
    	nvar = 111;
    	rvar = 222;
    	vvar = 333;
    
    	if (setjmp(env) == 0) {
    		nvar = 777;
    		rvar = 888;
    		vvar = 999;
    		doJump(nvar, rvar, vvar);
    	} else {
    		printf("After longjmp(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    	}
    	
    	return 0;
    }
    
    void doJump(int nvar, int rvar, int vvar) {
    	printf("After longjmp(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    	longjmp(env, 1);
    }
    

    image-20201218144324427

    预想输出两次应该均为 777 888 999

    由于优化器对代码重组受到longjmp()影响,所以输出不一致。

    解决: 在非局部跳转代码内使用显示声明volatile声明,让编译器不要优化变量

    习题

    6-1

    编译程序清单6-1中的程序,使用ls -l命令显示可执行文件的大小,解释为什么可执行文件的大小远小于10MB,但是程序中包含了一个10MB的数组?

    #include <stdio.h>
    
    char globalBuf[65535];
    
    void overstack();
    
    int main(int argc, char *argv[])
    {
    	overstack();
    	return 0;
    }
    
    void overstack() {
    	char overBuf[1024*1024*10]; // 申请10MB大小的容量
    }
    

    编译: 17K大小,显然程序中有两个大的未初始化的数据段,这些数组在程序运行时才会被分配存储空间。只有被初始化的数据段才会使得程序体积变大。

    char globalBuf[65535] = {0,1,2};
    

    此时81K

    char mbuf[10240000] = {0,10,0,1};
    

    使用如上的声明方式,不占用数据段,数组中剩余部分的0不占用程序体积,数组中的内容在文本段,占用程序体积,变量记录在栈中,在运行中将文本段拷贝到栈中,现在是8.8k,注意实际上体积仍然变大了,因为文本段增加了。程序无法运行,因为overBuf在栈中申请10MB大小,会超出一般系统提供的栈的大小。

    image-20201218150620296

  • 相关阅读:
    使用ALAssetsLibrary读取所有照片
    dispatch_after中时间的计算
    UICollectionView的header悬停
    ios侧滑返回:完美解决 interactivePopGestureRecognizer 卡住的问题
    自定义TabBar
    automaticallyAdjustsScrollViewInsets(UITextView文字顶部留有空白)
    kvo&kvc
    调用iPhone的短信
    Windows 10中Oracle数据库导出到Access数据库(MDB)
    HP Z620 Windows 7 系统安装(含磁盘阵列)
  • 原文地址:https://www.cnblogs.com/nsfoxer/p/14348119.html
Copyright © 2011-2022 走看看