Mach-O、Universal Binary、虚拟内存等简介

什么是Mach-O?

Mach-O:Mach Object,是Mac\iOS上用于存储程序、库的标准格式

属于Mach-O格式的文件类型有:11种

#define MH_OBJECT   0x1     /* Target 文件:编译器对源码编译后得到的中间结果 */
#define MH_EXECUTE  0x2     /* 可执行二进制文件 */
#define MH_FVMLIB   0x3     /* VM 共享库文件(还不清楚是什么东西) */
#define MH_CORE     0x4     /* Core 文件,一般在 App Crash 产生 */
#define MH_PRELOAD  0x5     /* preloaded executable file */
#define MH_DYLIB    0x6     /* 动态库 */
#define MH_DYLINKER 0x7     /* 动态连接器 /usr/lib/dyld */
#define MH_BUNDLE   0x8     /* 非独立的二进制文件,往往通过 gcc-bundle 生成 */
#define MH_DYLIB_STUB   0x9     /* 静态链接文件(还不清楚是什么东西) */
#define MH_DSYM     0xa     /* 符号文件以及调试信息,在解析堆栈符号中常用 */
#define MH_KEXT_BUNDLE  0xb     /* x86_64 内核扩展 */

常见的Mach-O类型有:

  • MH_OBJECT:目标文件.o静态库文件.a

程序员编写的.c或者.m文件,最后经过编译,将每个.c或.m文件转换为目标文件.o;再经过链接,将所有.o文件链接起来,形成可执行文件,程序就可以运行了

.a文件,其实就是多个源文件编译后的.o文件的集合

  • MH_EXECUTE:可执行文件

打出的包,是.ipa文件,在.ipa文件里面,有.app文件,再里面还有可执行文件

  • MH_DYLIB:动态库文件.dylib.framework/...

.dylib是MH_DYLIB类型的Mach-O格式
framework里面的文件,拿出来也是MH_DYLIB类型的Mach-O格式

  • MH_DYLINKER:动态链接编辑器.dyld

.dyld的作用:专门用来加载动态库文件

  • MH_DSYM:存储着二进制文件符号信息的文件:常用户分析APP的崩溃信息

Mach-O的基本结构

一个Mach-O格式的文件,包含三个主要区域:

  1. Header
  2. Load Commands
  3. Raw Segment Data

在这里插入图片描述

1. Header

文件类型、目标架构类型等

文件类型,就是前面讲到的11种类型
目标架构类型,是指Mach-O格式文件,是要放在哪个架构类型上执行的

2. Load Commands

描述文件在虚拟内存中的逻辑结构、布局

描述有多少个段,每个段的起始位置、有多大等信息

我们平时说的内存,其实都是虚拟内存,而不是实际的物理内存
另外,内存是分段管理的,也就是常说的五大区域:
代码段、常量段、全局(静态区)、堆、栈

Load Commands可以看做一个指针,指向的真正的位置,就是Segment Data

3. Raw Segment Data

Raw:原生的、原始的
Segment:段
Data:数据
在Load Commands中定义的Segment的原始数据

Mach-O有啥用?

通过了解Mach-O里面的内容,可以破解、修改别人的app文件
可以看到别人用到了哪些动态库?地址在哪?

怎样查看Mach-O里面的信息?

可以使用苹果自带的otool去查看
也可以使用MachOView

在这里插入图片描述

dyld与Mach-O

Mach-O有11种类型,其中有一些类型是由dyld加载到内存的

APP的可执行文件、动态库都是由dyld负责加载的

  • MH_EXECUTE
  • MH_DYLIB
  • MH_BUNDLE

Universal Binary(通用二进制文件)

通用二进制文件:

  • 同时适用于多种架构的二进制文件
  • 包含了多种不同架构的独立的二进制文件
  • 因为需要存储多种架构的代码,通用二进制文件通常比单一平台二进制文件要大
  • 由于多种架构有共同的资源,所以并不会比多个二进制文件的和还大
  • 由于执行过程中,只调用一部分代码,运行起来也不需要额外的内存
  • 由于文件比原来的要大,也被称为“胖二进制文件”(Fat Binary)
  • 多个二进制文件可以合成通用二进制文件,通用二进制文件也可以拆分出单独的二进制文件

我们Xcode打出的包,要在各个型号上的手机上跑,极端例子是:一个iphone4一个iphone15,两个架构不一样,但都要能跑。
之前的手机可能是32位的arm_v7,现在的手机可能是64位的arm64
只编译一套二进制文件是不行的,因此,我们需要编译两套或多套二进制文件
然后,将多套二进制文件,合并成一个通用的二进制文件


虚拟内存

我们程序所使用的内存地址叫做虚拟内存地址(Virtual Memory Address)
实际存在硬件里面的空间地址叫物理内存地址(Physical Memory Address)

用户编制程序时使用的地址称为虚地址或逻辑地址,其对应的存储空间称为虚存空间或逻辑地址空间;
而计算机物理内存的访问地址则称为实地址或物理地址,其对应的存储空间称为物理存储空间或主存空间。

为何需要虚拟内存?

物理内存有何弊端?

在计算机系统中,为了充分使用内存资源并保护每个进程内存空间不受其他进程的影响,硬件和操作系统通常提供虚拟内存机制。

虚拟内存的产生主要是为了解决物理内存容量有限和内存管理复杂性等问题。引入虚拟内存后,它为计算机带来了以下主要好处和解决方案:

1. 扩大可用内存空间

物理内存(RAM)的容量是有限的,而虚拟内存可以使用磁盘空间作为内存使用的扩展,从而提供了远超过物理内存限制的地址空间。这允许更大或更多的程序同时运行,提高了计算机的利用率和效率。

2. 内存管理的灵活性

虚拟内存允许操作系统更灵活地管理内存资源。每个程序都可以认为自己拥有一大块连续的内存区域,这简化了程序的内存管理,因为程序不需要关心物理内存的实际分配情况。

3. 提高了系统的安全性和稳定性

通过虚拟内存,操作系统可以为每个运行的程序提供独立的内存空间,从而实现进程间的内存隔离。这意味着一个程序出错不会影响到其他程序的运行,增加了系统的稳定性和安全性。

4. 实现内存的按需分配

虚拟内存支持按需分页(demand paging),即只有程序访问到的内存页才会被加载到物理内存中。这种按需分配的机制减少了物理内存的浪费,提高了内存使用效率

5. 支持内存共享和复制写

虚拟内存机制支持多个进程共享相同的物理内存页(如代码库或程序的只读数据),同时利用写时复制(copy-on-write)技术,当内容被修改时,才为各个进程创建私有的内存页。这进一步提高了内存使用的效率和程序间的协作。

总的来说,虚拟内存通过在物理内存和磁盘之间动态调配空间,解决了物理内存大小限制问题,同时提供了更高效、更安全、更灵活的内存管理策略。

虚拟内存是什么?

虚拟内存是一种内存管理技术,它的设计初衷是让每个程序都认为它独占了所有的物理内存。操作系统和计算机硬件将物理内存抽象化出一个被称为虚拟内存的概念,每个程序实际使用的内存地址都是这个虚拟内存空间的一部分。分页机制使得每个程序都像有着连续的内存空间一样,但实际下这些连续的虚拟内存可能在物理内存中是不连续的。

在这里插入图片描述

虚拟内存系统的关键组成部分是页表,页表记录了虚拟地址和物理地址的对应关系。CPU产生的每个内存访问都必须通过页表查询和转换,从而获得真正的物理内存地址。

虚拟内存的主要优缺点:

虚拟内存的主要优点有:

  1. 程序的大小不再受物理内存大小的限制,而是由更大的磁盘存储空间决定。
  2. 让程序员无需关注物理内存的分配和管理问题。
  3. 程序之间互相隔离,保护了系统的稳定性和安全性。
  4. 支持了内存的按需分配和分页交换,使得内存使用更加高效。

虚拟内存的主要缺点有:

  1. 管理虚拟内存增加了系统的复杂性,页表查询和页交换操作需要占用CPU资源。
  2. 如果程序频繁访问的内存页不在物理内存中,而在磁盘上,就会带来很高的页错误(page fault)开销。
  3. 程序如果不能有效地利用局部性原则(locality principle),虚拟内存系统带来的性能开销就会增大。

虚拟内存的管理方式:

分段、分页、段页式

1. 分段

就是我们平时说的五大内存区的分法
在这里插入图片描述

分段的办法很好,解决了程序本身不需要关心具体的物理内存地址的问题,但它也有一些不足之处:

  • 第一个就是内存碎片的问题。
  • 第二个就是内存交换的效率低的问题。

2. 分页

在虚拟内存系统中,通常采用分页(Paging)的方式来管理和分配内存。

分页是指将物理内存划分为一系列固定大小的页(Page),每个页的大小通常为4KB。同样,虚拟内存也被划分为一系列的虚拟页。操作系统和硬件保持一个页表,用来记录虚拟页和物理页的对应关系。
在这里插入图片描述

而当需要访问某个内存位置时,会使用一个虚拟地址。该虚拟地址可以分为两个部分,一页的虚拟页号(也称为页帧号)和一个在当前页内部的偏移量(Offset)。

以32位系统为例,如果我们假设页面大小是4KB(2的12次方),那么我们可以使用32位地址的前20位作为页帧号,后12位作为当前页内部的偏移量。页帧号用来查找页表,确定虚拟页面在物理内存中的位置;偏移量则用来在找到的物理页中定位具体的数据。

这样,通过分页机制,大大简化了内存管理,同时也使得每个进程都有一致和连续的地址空间,虽然这些地址空间的实际物理位置可能非常的不连续。

3. 段页式

内存分段和内存分页并不是对立的,它们是可以组合起来在同一个系统中使用的,那么组合起来后,通常称为段页式内存管理。

在这里插入图片描述


参考资料:
一文带你了解,虚拟内存、内存分页、分段、段页式内存管理

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值