Linux_程序到进程-内存模型和进程管理
操作系统
术语: 数据区,堆,栈,静态区,常量区,全局区,字符串常量区,文字常量区,代码区等等
数据区包括 :堆,栈,全局/静态存储区。
全局/静态存储区包括:常量区,全局区、静态区。
常量区包括 :字符串常量区、常变量区。
代码区 :存放程序编译后的二进制代码,不可寻址区
程序到进程
1.可执行程序 需要有固定的格式
windows中可执行文件是PE格式的,以exe作为后缀结尾
linux可执行文件是ELF格式的,
Mach-O:常用于macOS系统
2.load-加载器通过可执行文件头部信息,找到程序的入口点
文件解析 --内存分配---文件映射--符号解析
内存布局 处理器从内存取指令和操作数,- 加载段到内存
外部存储设备是内存的后备存储设备。外部存储设备的内容只有被加载到内部存储设备中后才能被访问
先加载到内存的高速缓存区 ,从高速缓存区读取文件头,里面存了代码段、数据段的起始和size信息
加载器通过可执行文件头部信息,找到程序的入口点 加载共享库 设置进程环境 跳转到入口
运行时库初始化(如C运行时库)。
初始化全局对象(尤其是在C++中)
应用程序加载器Loader
3.跳转程序的入口点,然后OS将CPU控制权交给新创建的进程
执行 fork/exec
fork()系统调用会通过复制一个现有进程来创建一个全新的进程
fork()函数:这是Unix/Linux系统中的一个系统调用,可以创建一个新的进程。
在调用fork()函数后,父进程会创建一个子进程,两个进程将在fork()调用的位置继续执行。
exec()函数族:在子进程中,可以使用exec()函数族中的一个函数来加载一个新的可执行文件,并在当前进程空间中执行它。
exec()函数会取代当前进程的代码和数
wait():
用在父进程中等待子进程结束后,回收子进程,解除阻塞;若子进程一直没有退出,则阻塞住父进程
exit和_exit:中止当前进程。exit()会先清理环境并调用终止处理程序,而_exit()不会进行任何清理直接终止进程
文件
程序源代码被编译之后主要分成两种段:
程序指令(代码区)和程序数据(数据区)。
代码段属于程序指令,而数据域段和.bss段属于程序数据
ELF(Executable Linkable Format)
对象文件(Object files)有三个种类: 可重定位文件( Relocatable File) 可执行文件 可共享文件
ELF文件格式提供了两种视图,分别是链接视图和执行视图
链接视图是以节(section)为单位,执行视图是以段(segment)为单位
构成:ELF文件由4部分组成,
分别是ELF头(ELF header)、程序头表(Program header table)、节/段(Section/Segments)和节头表(Section header table )
segments是从运行的角度来描述elf文件,sections是从链接的角度来描述elf文件,一个segment包含若干个section
两种不同的ELF格式映像
一种是静态链接的,在装入/启动其运行时无需装入函数库映像、也无需进行动态连接。
另一种是动态连接,需要在装入/启动其运行时同时装入函数库映像并进行动态链接。
ELF 文件加载
ELF文件的动态加载机制主要依赖于动态链接器(dynamic linker),也称为动态加载器(dynamic loader)。
Linux系统中通常是`/lib/ld-linux.so.2`
动态链接器负责在程序运行时解析ELF文件中的动态链接信息,加载所需的共享库,并完成符号解析和重定位过程
内存模型
C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
#####
程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、数据区(data)和未初始化数据区(bss)3 个部分
运行可执行程序,操作系统把物理硬盘程序load(加载)到内存,
除了根据可执行程序的信息分出代码区(text)、数据区(data)和未初始化数据区(bss)之外,
还额外增加了栈区、堆区
分区模型
重排序
编译优化重排序 指令并行重排序 CPU 缓存
编译器有关(编译优化重排序)、与处理器有关(指令并行重排序、CPU 缓存)、与并发有关(CPU 缓存)
内存屏障
依赖于操作系统std中的大部分内容(io, thread, file system, etc.)都需要操作系统的支持
不依赖于操作系统的rust的语言特性我们还是可以继续使用
内存模型
操作系统内存模型--内核的内存模型
内存的访问一致性(consistency/coherence)模型
内核中提供的各种内存屏障
从反编译视角学习内存模型
Cangjie内存模型
3.仓颉语言支持自动内存管理,通常通过垃圾回收机制来管理内存的分配和释放
Rust
Rust编程语言以其独特的内存管理机制而著称,
这一机制基于所有权(Ownership)、借用(Borrowing)和生命周期(Lifetimes)的概念
Go语言
内存模型的目的是为了定义清楚变量的读写在不同执行体里的可见性。理解内存模型在并发编程中非常重要
Go的并发模型是基于CSP(Communicating Sequential Process)的,不同的Goroutine通过一种叫Channel的数据结构来通信;
Java的并发模型则基于多线程和共享内存,有较多的概念(violatie, lock, final, construct, thread, atomic等)和场景
Java内存模型
1.
2.Java中,程序的加载、链接和初始化过程由JVM(Java虚拟机)负责。
这个过程主要是通过类加载器(Class Loader)和其相关子系统来完成的
3.JVM内存模型其实就是
JVM在启动的时候从操作系统内存中要了一块大内存,然后将这个大内存分成
五个区域:方法区、堆区、虚拟机栈、本地方法栈、本地方法栈、程序计数器.
其实叫JVM运行时区域更合适。但是要区分JVM内存模型与JMM(Java Memory Model)
让用户能控制的都是安全稳定的,有风险的操作都在门面之后,保证了操作系统的相对安全
Python内存模型
Python 在Python中,对象是核心概念之一。理解对象的基本组成和内存模型
类型(Type) 值(Value):对象的实际数据 引用计数(Reference Count)
Python使用引用计数来实现内存管理,当一个对象的引用计数为0时,内存将被回收。

浙公网安备 33010602011771号