Linux内存总结

内存相关
  开发环境
    编译器
      gcc编译器
        什么是编译器:把人类能看的懂的语言翻译成机器能够看的懂的二进制语言的程序。
        编译器
          预处理器:把程序员编写的代码翻译成标准的C语言。
          翻译器:把标准的C语言编程成二进制语言(没有入口)。
          链接器:把若干个目标文件合并在一起生成可执行的二进制文件。
          装载器:把可执行的二进制文件按照操作系统要求装载到内存并开始执行(程序员的自我修养)。
        gcc编译器是GNU社区为了编译Linux内核开发的一套编译框架,不光能编译C语言,包括C++、java、Objective-C。
        常用的参数
          -E 只预处理,处理后的结果直接显示在屏幕上,如果需要保存需要加参数-ofile.i
          -c 只翻译不链接,只生成目标文件file.o
          -o 为编译出的结果重新命名。-o file
          -Wall 尽可能多的产生警告,编译检查更严格。
          -Werror 把警告当错误处理,如果有警告则不能再生成可执行程序。
          -g 生成调试信息,要与gdb配合使用。
          -S 生成汇编文件file.s
          -D 在编译时定义宏
        源码变成可执行程序的过程
          1、编写源码,vim code.c
          2、预处理生成以.i结尾的预处理文件,gcc -E code.c -o code.i
          3、生成.s结尾的汇编文件,gcc -S code.i -> code.s
          4、生成以.o结尾的目标文件,gcc -c code.s -> code.o
          5、链接(ld)若干个.o文件生成可执行程序,gcc a.o b.o c.o -> a.out(elf)
      GNU 编译框架
        支持众多编译语言
          C、C++、JAVA、Objective-C、Ada
        支持各种编译平台
          U L W
        构建过程(build)
          源代码变成可执行程序的过程a.c->a.out
            编写.c文件
            预处理 gcc -E a.c ->a.i
            汇编 gcc -S a.i 生成 a.s
            编译 gcc -C a.s 生成 a.o
            链接 gcc a.o libstd.o 生成 a.out
        gcc -v 查看编译器版本信息
          Ubuntu 12.04 LTS
          编译的版本号 gcc 版本4.6.3
          编译的位数i686-linux-gnu
          所支持的语言C、C++
        头文件路径:/usr/include
      文件类型
        .c
          源代码文件
        .h
          头文件
        .i
          预处理文件
        .s
          汇编文件
        .o
          目标文件
        .a
          静态库文件
        .so
          共享库文件
        .gch
          编译后的头文件
          file.h file.gch (优先使用)
      编译单个文件
        -C
          只编译不链接
        -E
          预处理
        -S
          汇编
        -Wall
          尽可能多的生成警告信息
        -Werror
          把警告信息当做错误处理
        -g
          生成调制信息
        -x
          指定要编译的语言
        -pedantic
          以ANSI标准检查语法,一旦出扩展的语法就会出现警告
      编译多个文件
        头文件的作用
          声明外部变量和外部函数
          定义宏常量、宏函数
          类型设计、类型重定义
          包含其他头文件
          借助“头文件卫士”防止重复包含
        防止头文件相互包含
          定义c.h,把a.h和b.h中的共用部分移动到c.h
        包含头文件和不包含头文件的区别
          如果没有头文件,编译器会猜测函数的格式(返回值int,参数按实参的类型猜测)
          #include""先在当前目录下查找,如果找不到再去系统指定的位置找
          #include<>系统指定的位置去找头文件
          编译器也可以指定头文件的查找路径 -I path
        编译单个.c文件,然后再合并成可执行文件
          gcc -c code.c->code.o
          gcc code.o->a.out
        编写Makefile脚本
      预处理指令
        #include
          包含头文件
        #define
          定义宏常量或宏函数
        #undef
          取消宏定义
        #if
          判断
        #else
          当#if为假时再次判断
        #elif
          与#if配合使用
        #endif
          结束判断
        #ifndef
          判断没有定义宏
        #ifdef
          判断定义宏
        ##
          连接两个标识符形成一个新的标识符
        #
          把参数转换成字符串字面值
        #error
          生成错误信息
        #waring
          生成警告信息
        #pragma pack (2)
          结构体超过2字节的,按照2字节对齐
        #pragma GCC poison key
          把key设置为病毒,禁止使用
        #line
          设置代码的行号
        如何在命令行定义宏:gcc -D 宏名=数值
      预定义的宏
        __BASE_FILE__
          当前正在编译的文件名
        __FILE__
          代码所在的文件名
        __LINE__
          获取行号
        __FUNCTION__
          获取函数名
        __func__
        __DATA__
          获取日期
        __TIME__
          获取时间
        __cplusplus__
          用户判断编译器的语法是否是C++
      与编译器相关的环境变量
        vi~/.bashrc
        C_INCLUDE_PATH
          设置C语言头文件路径
        CPATH
          设置C语言头文件路径
          export CPATH=/home/zhizhen
        LIBRARY_PATH
          设置库文件路径(编译时)
        LD_LIBRARY_PATH
          动态加载库文件路径(运行时)
        添加环境变量:source ~/.bashrc
        删除环境变量要关闭终端重新打开才有效
    库
      库(库文件):把若干个目标文件合并在一起形成的集合,就是代码的集合
        分久必合(方便使用),合久必分(文件维护)
        库文件的分类
          静态库
            调用者把所需的代码从静态库中直接拷贝到可执行文件中 .a
          共享库(动态库)
            调用者吧所需的代码先在共享库中确认,当执行时会把共享库和可执行文件一起加载,当需要执行共享库中的代码时直接从可执行文件中跳转过去 .so ,dll
          静态库:编译出的静态库相对比较大,不易修改(静态库的代码会变,可执行文件要重新编译),但执行效率高
          共享库:编译出的共享库相对比较小,容易修改(共享库发生改变,程序不用重新编译),但执行效率不高
      代码库
        长年代码的积累
    静态库
      创建静态库
        gcc - c code.c ->code.o
        ar -r libname.a code.o ...
      调用静态库
        静态库是需要与调用者一起编译(拷贝)
        直接调用(调用者与库在同一目录下)
          gcc hello.c libname.a
        设置LIBRARY_PATH,配合-lname
          vi ~/.bashrc
          export LIBRARY_PATH=$LIBRARY_PATH:/home/zhizhen
          gcc hello.c -lname
        -Lpath配合-lname
          gcc hello.c -Lpath -lname
      ar命令
        -r 生成静态库
        -q 往静态库中追加目标文件
        -d 从静态库中删除目标文件
        -t 显示静态库中所有的目标文件
        -x 把静态库展开成目标文件
    共享库
      创建共享库
        -fpic 位置无关,代码段的地址都使用的是相对位置
          gcc -fpic -c code.c->code.o
          gcc -shared -o libname.so code.o ...
      调用共享库
        与调用静态库的库方法一致
      共享库的运行
        调用共享库的可执行文件,运行时需要共享库一起加载并执行
        运行时查找共享库需要从LD_LIBRARY_PATH指定
        export LD_LIBRARY_PATH=$LD_LIBRARY:~/math/
      共享库相关命令
        -fpic
          小模式:生成的位置无关目标文件相对较小,速度较快,但只有个别平台支持
        -fPIC
          大模式:生成的位置无关目标文件相对较大,速度较慢,基本所有平台都支持
        ldd
          查找可执行文件所依赖的共享库文件
        ldconfig
          LD_LIBRARY_PATH环境变量所配置的路径会记录到ld.so.conf,每次开机时会共享库加载到ld.so.cache文件中,以此来提高共享库的运行速度,ldconfig可以重新生成ld.so.cache文件,而不用等到开机
          sudo ldconfig
      动态加载共享库
        在编译时不再查找共享库,在运行时才去查找并加载共享库
          要依靠环境变量
        #include<dlfcn.h>
        打开共享库
          void *dlopen(const char *filename,int flag);
            filename:库名或路径,如果只有库名则去LD_LIBRARY_PATH环境变量指定的位置查找
            flag:
              RTLD_LAZY 延时加载,使用时才加载
              RTLD_NOW 立即加载,程序执行时就被加载
            返回值:成功返回共享库的句柄,失败返回NULL
        dlsym:查找函数
          void *dlsym(void *handle,const char *symbol);
            handle:共享库的句柄,dlopen的返回值
            symbol:函数名
            返回值:成功返回函数指针,失败返回NULL
        dlclose:关闭共享库
          int dlclose(void *handle);
            handle:共享库的句柄,dlopen的返回值
            返回值:0关闭成功,非零失败
        dlerror:查看错误
          char *dlerror(void)
            当dlopen、dlsym、dlclose执行出错,再调用此函数获取错误信息
        gcc test.c -ldl
          l表示调用库
          dl表示动态库
    辅助工具
      nm
        查看目标文件、静态库、共享库、可执行文件中的符号列表
      strip
        删除目标文件、静态库、共享库、可执行文件中的符号列表
      objdump
        显示二进制模块的汇编信息
  内存管理
    环境变量
      什么是环境变量
        是程序了解操作系统配置的一个重要方法
          操作系统通过环境变量来告诉程序的资源放在什么位置
      每个程序执行后操作系统就给它一张环境变量表,每个程序一张
      全局变量 extern char** environ
      也可以通过main函数参数来获取
        int main(int argc,char** argv,char** env)
      操作环境变量的函数:
        stdlib.h
        name=value
        char *getenv(const char *name);
          通过环境变量名获取环境变量值
        int putenv(char *string);
          以name=value来设置环境变量,如果环境变量已经存在则覆盖,不存在则添加
        int setenv(const char *name,const char *value,int overwrite);(返回0成功,非0失败)
          以name,value方式来设置环境变量
          name:环境变量名
          value:环境变量值
          overwrite:如果环境变量已经存在,为0则不改变,不为0则改变
        int unsetenv(const char *name)
          删除环境变量
        int clearenv(void);
          清空环境变量表

    错误处理
      通过函数返回值表示错误
        合法或不合法
          数组的查找
          计算文件的大小
            int file_size(const char* path);
            调用ftell函数获取文件位置指针
            设置文件位置指针到文件末尾
        NULL或其他地址
          malloc、fopen、dlopen
          实现mem_cpy功能
            void *mem_cpy(void *dest, const void *src, size_t n);
            dest与src可能会有交集
        成功返回0,失败返回-1 bool
          bool top_stack(Stack* stack,TYPE* top);
          dlclose
          实现求余函数
            int mod(int num1,int num2,int* retp);
        永远成功
          printf
        通过全局变量来反映错误
          errno.h
          erron
          strerror(erron)
          perror(fopen)
    重定义
      #define TYPE int*
      typedef int* TYPE;重命名
      TYPE p1,p2,p3
    内存管理
      用户层
        STL智能指针/自动分配/分支释放
        C++ new/delete
        C malloc/calloc/realloc/free
        posix sbrk/brk 操作系统提供的内存管理方式
        Linux mmap/munmap
      内核层
        kernel
          kmalloc/vmalloc
        Driver
          get_free_page
        DDR4
    进程的映像
      存储在磁盘中的可执行文件叫程序
      把程序加载到内存中并执行,叫进程,进程可以看作是可执行程序的一个实例
      一个程序可以有很多个实例,每个进程都有一个唯一的编号
        getpid();
      进程在内存中的分布情况叫进程映像,从低到高依次排列情况
        代码段
          可执行文件会被加载到此处
        只读段
          字面值、常量
        全局段
          初始化过的全局变量、静态变量
        bss段
          未初始化的全局变量、静态变量
        堆
          new/delete/malloc/sbrk
        栈
          局部变量、块变量、函数的返回值
        命令行/环境变量 (最高)
          命令行执行程序时附加的参数,环境变量表
        /proc/pid/maps 可以查看内存的分布情况
        size a.out 可以查看代码段、全局段、bss段的大小
    虚拟内存
      每个进程都有独立的4G(320S)的虚拟地址空间
        0x00000000
        0xffffffff
      应用程序中用到的都是虚拟内存,永远无法访问到实际的物理内存
      虚拟内存不能直接使用,需要与物理内存建立映射关系才能使用,使用没有建立映射关系的虚拟内存将发生段错误
      虚拟内存与物理内存的映射是由操作系统动态维护,由操作系统统一内存的管理能提高程序和系统的安全性,还可以使用更多的内存,甚至比物理内存更大的内存。
      物理内存不能直接访问,是通过系统调用进入到内核层,然后再进行间接交换
      虚拟地址的0~3G用户使用,3~4G内核使用
        8bit=1byte
      在使用没有权限的内存时会发生段错误,使用没有映射过的内存会发生段错误
      每个进程对应一个虚拟地址空间,两个进程之间进行地址交换是没有意义的
      malloc背后有一个双向链表在维护它的内存管理,首次向malloc申请内存时,malloc会向操作系统申请进行内存映射(首次映射33页,1页默认4096byte)。之后的内存分配就从这33页中进行,当33页用完后,操作系统会再次映射33页
        当使用malloc进行内存管理时,不要破坏维护信息
        可能会影响下次内存的分配和之前内存的释放
      内存的映射是以页(4096byte)为单位,一页内存的字节数可以通过getpagesize()获取
    Linux内存映射函数
      mmap
        void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset)
          addr
            想与物理内存映射的虚拟地址,如果是NULL可以让操作系统自动选择
          length
            映射的字节数,以页为单位
          prot
            映射的权限,读写执行
              PROT_EXEC
              PROT_READ
              PROT_WRITE
              PROT_NONE
          flags
            MAP_SHARED 映射文件
            MAP_PRIVATE 数据只写入缓冲区,不更新到文件
            MAP_ANON 只映射内存
          fd
            映射文件时,文件描述符,如果不映射文件,写0
          offset
            映射文件时的偏移值,如果不映射文件,写0
          返回值
            映射后的内存的地址
      munmap
        int munmap(void *addr,size_t length);
          addr
            要取消映射的地址
          length
            字节数
          返回值
            成功返回0,失败返回非零
    POSIX的内存管理函数
      sbrk和brk维护一个内存末尾指针
      sbrk
        void *sbrk(intptr_t increment);
          increment 把内存的末尾指针移动increment个字节
          返回值:上次调用sbrk/brk的内存末尾指针
      brk
        int brk(void *addr);
          把内存末尾指针设置为addr
          返回值0表示成功,非零表示失败

原文地址:https://www.cnblogs.com/yanxutao/p/9419023.html

时间: 2024-10-05 20:10:03

Linux内存总结的相关文章

linux内存管理

一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程序可调用它.假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段.     2) 数据段:存放已初始化的全局变量.静态变量(包括全局和局部的).常量.static全局变量和static函数只能在当前文件中被调用.     3) 未初始化数据区(uninitializeddata s

Linux内存管理机制

一.首先大概了解一下计算机CPU.Cache.内存.硬盘之间的关系及区别. 1.  CPU也称为中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路, 是一台计算机的运算核心(Core)和控制核心( Control Unit).它的功能主要是解释计算机指令以及处理计算机软件中的数据.中央处理器主要由三核心部件组成,运算器.控制器和总线(BUS),运算器又主要由算术逻辑单元(ALU)和寄存器(RS)组成. 2.Cache即高速缓冲存储器,是位于CPU与主内存

Linux内存机制以及手动释放swap和内存

哇,感觉好久没更新了,今天我们来谈谈Linux的内存机制. 首先我们理一下概念 一.什么是linux的内存机制? 我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念. 物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换

Linux内存管理 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4491368.html Linux内存管理 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在本章最后,我们给出一个内存映射的实例,帮助网友们理解内核内存管理与用户内存管理之间的关系,希望大家最终能驾驭Linux内存管理. 前言 内存管理一向是所有操作系统书

攻城狮在路上(叁)Linux(二十五)--- linux内存交换空间(swap)的构建

swap的功能是应付物理内存不足的状况,用硬盘来暂时放置内存中的信息. 对于一般主机,物理内存都差不多够用,所以也就不会用到swap,但是对于服务器而言,当遇到大量网络请求时或许就会用到. 当swap被使用的时候,主机的硬盘灯就会闪烁不停. 本篇介绍两种方式:1.设置一个swap分区   2.创建一个虚拟内存的文件. 一.使用物理分区构建swap: 1.首先是分区: A.fdisk /dev/sda; <== 根据后续提示创建一个分区. B.修改分区的ID,因为fdisk默认将分区的ID作为文件

linux内存管理浅析

[地址映射](图:左中)linux内核使用页式内存管理,应用程序给出的内存地址是虚拟地址,它需要经过若干级页表一级一级的变换,才变成真正的物理地址.想一下,地址映射还是一件很恐怖的事情.当访问一个由虚拟地址表示的内存空间时,需要先经过若干次的内存访问,得到每一级页表中用于转换的页表项(页表是存放在内存里面的),才能完成映射.也就是说,要实现一次内存访问,实际上内存被访问了N+1次(N=页表级数),并且还需要做N次加法运算.所以,地址映射必须要有硬件支持,mmu(内存管理单元)就是这个硬件.并且需

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1

linux内存源码分析 - 内存压缩(同步关系)

本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也那么复杂吧,带着好奇心就把页面迁移的源码都大致看了一遍,还好,不复杂,也容易理解,这里我们就说说在页面迁移过程中是如何进行同步的.不过首先可能没看过的朋友需要先看看linux内存源码分析 - 内存压缩(一),因为会涉及里面的一些知识. 其实一句话可以概括页面迁移时是如何进行同步的,就是:我要开始对这

手工释放linux内存

当在Linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching.这个问题,貌似有不少人在问,不过都没有看到有什么很好解决的办法.那么我来谈谈这个问题.一.通常情况先来说说free命令:引用[[email protected] ~]# free -m         total used free shared buffers cachedMem: 249 163     86      0        10           94-/+ b

Cgroup - Linux 内存资源管理

Hi ,我是 Zorro .这是我的微博地址,我会不定期在这里更新文章,如果你有兴趣,可以来关注我呦. 另外,我的其他联系方式: Email: [email protected] QQ: 30007147 本文PDF 在聊 cgroup 的内存限制之前,我们有必要先来讲解一下: Linux 内存管理基础知识 free 命令 无论从任何角度看, Linux 的内存管理都是一坨麻烦的事情,当然我们也可以用一堆.一片.一块.一筐来形容这个事情,但是毫无疑问,用一坨来形容它简直恰当无比.在理解它之前,我