为何百兆静态库能打进数兆的可执行文件?

第三方库是工程开发必不可少的部分,而第三方库可以是.a和.framework的静态库,也可以是.framework的动态库,其中静态库是最常用的方式。
静态库往往比较大,可在打包到可执行文件之后,对安装包大小的增加远远小于静态库本身的Size。
那么,就产生两个问题:
1、静态库里面存在什么内容?
2、静态链接到可执行文件后为什么体积变小?
本文就以.framework的静态库来分析具体情况。

正文

1、framework静态库的打包

新建工程,选择Cocoa Touch Framework,再到Build Settings选择Mach-O TypeStatic Library,然后build出来目标文件就是framework静态库。

2、framework静态库的内容

按照上面的步骤打包出来的LYTestKit.framework,具体的内容如下:

  • Headers为头文件;
  • plist文件和Modules文件夹是一些描述文件;
  • LYTestKit为Mach-O binary文件,LYTestKit占了静态库99%的体积。



 

4、静态链接的过程

静态连接就是把静态链接库中的文件链接到可执行文件中,整个过程由链接器负责。
链接过程分为两步:

  • 1、空间和地址分配,扫描所有的目标文件,获得各个段的长度、属性、位置信息,并把所有的符号定义以及引用收集起来,放到全局的符号表中。通过所有段的长度,计算和合并后的长度和位置,并建立映射关系;
  • 2、符号解析和重定位,使用上一步收集到的信息,读取文件中段的数据和重定位信息,进行符号解析和重定位。


 

静态库链接过程体积变小的答案

framework静态库在链接之后,体积会急剧减少,原因有几个:
1、用于链接的信息被剔除,比如说类引用、函数名等,字符信息中的函数名字等在链接时会放入链接表,用于查找地址,但不打入二进制文件;
2、调试用的信息比如符号串、代码行号等不会打入二进制包,而是额外生成符号表
3、Xcode默认在release下会用fastest的优化选项;

滑动验证页面

静态链接下可执行文件的生成

目标文件分成了三段,代码段,数据段,符号表,那么在静态链接下可执行文件的生成过程如图所示:

 

从上图中我们可以看到可执行文件的特点:

  • 可执行文件和目标文件一样,也是由代码段和数据段组成。
  • 每个目标文件中的数据段都合并到了可执行文件的数据段,每个目标文件当中的代码段都合并到了可执行文件的代码段。
  • 目标文件当中的符号表并没有合并到可执行文件当中,因为可执行文件不需要这些字段。

可执行文件和目标文件没有什么本质的不同,可执行文件区别于目标文件的地方在于,可执行文件有一个入口函数,这个函数也就是我们在C语言当中定义的main函数,main函数在执行过程中会用到所有可执行文件当中的代码和数据。

而这个main函数是被谁调用执行的呢,答案就是操作系统(Operating System),这也是后面文章当中要重点介绍的内容。

静态链接是使用库的最简单最直观的形式, 从静态链接生成可执行文件的过程中可以看到,静态链接会将用到的目标文件直接合并到可执行文件当中,想象一下,如果有这样的一种静态库,几乎所有的程序都要使用到,也就是说,生成的所有可执行文件当中都有一份一模一样的代码和数据,这将是对硬盘和内存的极大浪费,假设一个静态库为2M,那么500个可执行文件就有1G的数据是重复的。如何解决这个问题呢,答案就是使用动态库。

动态库

从名字中我们知道动态库也是库,本质上动态库同样包含我们已经熟悉的代码段、数据段、符号表。只不过动态库的使用方式以及使用时间和静态库不太一样。

在前面几个小节中我们知道,使用静态库时,静态库的代码段和数据段都会直接打包copy到可执行文件当中,使用静态库无疑会增大可执行文件的大小,同时如果程序都需要某种类型的静态库,比如libc,使用静态链接的话,每个可执行文件当中都会有一份同样的libc代码和数据的拷贝,如图所示,动态库的出现解决了此类问题。

clipboard.png

动态库允许使用该库的可执行文件仅仅包含对动态库的引用而无需将该库拷贝到可执行文件当中。也就是说,同静态库进行整体拷贝的方式不同,对于动态库的使用仅仅需要可执行文件当中包含必要的信息即可,为了方便理解,你可以将可执行文件当中保存的必要信息仅仅理解为需要记录动态库的名字就可以了,如图所示,同静态库相比,动态库的使用减少了可执行文件的大小。

clipboard.png

动态链接

我们知道静态库在编译链接期间就被打包copy到了可执行文件,也就是说静态库其实是在编译期间(Compile time)链接使用的,那么动态库又是在什么时候才链接使用的呢,动态链接可以在两种情况下被链接使用,分别是load-time dynamic linking(加载时动态链接) 以及 run-time dynamic linking(运行时动态链接),接下来我们分别讲解一下。

1,load-time dynamic linking(加载时动态链接)
首先可能有的同学会问,什么是load-time呢,load_time翻译过来也就是加载时,那么什么又是加载呢?
我们大家都玩过游戏,当我们打开游戏的时候经常会跳出来一句话:“加载中,请稍后。。。”和这里的加载意思差不多。这里的加载指的是程序的加载,而所谓程序的加载就是把可执行文件从磁盘搬到内存的过程,因为程序最终都是在内存中被执行的。至于这个过程的详解内容我会在接下来的文章《加载器与可执行文件》一文中给大家详细讲解。在这里我们只需要简单的把加载理解为程序从磁盘复制到内存的过程,加载时动态链接就出现在这个过程。

当把可执行文件复制到内存后,且在程序开始运行之前,操作系统会查找可执行文件依赖的动态库信息(主要是动态库的名字以及存放路径),找到该动态库后就将该动态库从磁盘搬到内存,并进行符号决议(关于符号决议,参考符号决议一节),如果这个过程没有问题,那么一切准备工作就绪,程序就可以开始执行了,如果找不到相应的动态库或者符号决议失败,那么会有相应的错误信息报告为用户,程序运行失败。比如Windows下比较常见的启动错误问题,就是因为没有找到依赖的动态库。Linux下同样会有类似信息提示用户程序启动失败。

clipboard.png

到这里,同学们应该对加载时动态链接应该有一个比较清晰的了解了。从总体上看,加载时动态链接可以分为两个阶段:阶段一,将动态库信息写入可执行文件;阶段二,加载可执行文件时依据动态库信息进行动态链接。

阶段一,将动态库信息写入可执行文件
在编译链接生成可执行文件时,需要将使用的动态库加入到链接选项当中,比如在Linux下引用libMath.so,就需要将libMath.so加入到链接选项当中(比如libMath.so放到了/usr/lib下,那么使用命令 gcc ... -lMath -L/user/lib ... 进行编译链接),所以使用这种方式生成的可执行文件中保存了依赖的动态库信息,在Linux可使用一个简单的命令ldd来查看。

阶段二:加载可执行文件时依据动态库信息进行动态链接
由于在阶段一生成的可执行文件中保存了动态库信息,当可执行文件加载完成后,就可以依据此信息进行中动态库的查找以及符号决议了。

通过这个过程也可以清楚的看到静态库和动态库的区别,使用动态库的可执行文件当中仅仅保留相应信息,动态库的链接过程被推迟到了程序启动加载时。

为加深你对加载时动态链接这个过程的理解,我们用一个类比来结束本小节,沿用前几节读书的例子,我们正在读的书中引用了《码农的荒岛求生》以及其它著作,那么加载时动态链接就好比,读者开始准备读这本书的时候(还没有真正的读)就把所有该书当中引用的资料著作都找齐放到一旁准备查看,当我们真正看到引用其它文献的地方时就可以直接在一旁找到该著作啦。在这个类比当中,开始读书前的准备工作就好比加载时动态链接。

2, 接下来我们讲解第二种动态链接,run-time dynamic linking(运行时动态链接) 。
run-time dynamic linking(运行时动态链接)
上一小节中我们看到如果我们想使用加载时动态链接,那么在编译链接生成可执行文件阶段时需要告诉编译器所依赖的动态库信息,而run-time dynamic linking 运行时动态链接则不需要在编译链接时提供动态库信息,也就是说,在可执行文件被启动运行之前,可执行文件对所依赖的动态库信息一无所知,只有当程序运行到需要调用动态库所提供的代码时才会启动动态链接过程。

我们在上一节中介绍了load-time,也就是程序加载时,那么程序加载完成后就开始程序执行了,那么所谓run-time(运行时)指的就是从程序开始被CPU执行到程序执行完成退出的这段时间。

所以运行时动态链接这种方式对于“动态链接”阐释的更加淋漓尽致,因为可执行文件在启动运行之前都不知道需要依赖哪些动态库,只在运行时根据代码的需要再进行动态链接。同加载时动态链接相比,运行时动态链接将链接这个过程再次推迟往后推迟,推迟到了程序运行时。

由于在编译链接生成可执行文件的过程中没有提供所依赖的动态库信息,因此这项任务就留给了程序员,在代码当中如果需要使用某个动态库所提供的函数,我们可以使用特定的API来运行时加载动态库,在Windows下通过LoadLibrary或者LoadLibraryEx,在Linux下通过使用dlopen、dlsym、dlclose这样一组函数在运行时链接动态库。当这些API被调用后,同样是首先去找这些动态库,将其从磁盘copy到内存,然后查找程序依赖的函数是否在动态库中定义。这些过程完成后动态库中的代码就可以被正常使用了。

相对于加载时动态链接,运行时动态链接更加灵活,同时将动态链接过程推迟到运行时可以加快程序的启动速度。

为了和加载时动态链接作比对,我们继续使用上一小节当中读书的例子,加载时动态链接就好比在开始准备读一本书之前,将该书中所有引用到的资料文献找齐全,而运行时动态链接则不需要这个过程,运行时动态链接就好比直接拿起一本书开始看,看到有引用的参考文献时再去找该资料,找到后查看该文献然后继续读我们的书。从这个例子当中运行时动态链接更像是我们平时读书时的样子。

至此,两种动态链接的形式我们就都已经清楚了,接下来我们看一下动态链接下生成的可执行文件。

动态链接下可执行文件的生成

在静态链接下,链接器通过将各个目标文件的代码段和数据段合并拷贝到可执行文件,因此静态链接下可执行文件当中包含了所依赖的所有代码和数据,而与之对比的动态链接下可执行文件又是什么样的呢?
其实我们在动态库这一节中已经了解了动态链接下可执行文件的生成,即,在动态链接下,链接器并不是将动态库中的代码和数据拷贝到可执行文件中,而是将动态库的必要信息写入了可执行文件,这样当可执行文件在加载时就可以根据此信息进行动态链接了。为方便理解,我们将该信息仅仅认为是动态库都名字,真实情况当然要更复杂一点,这里我们以Linux下可执行文件即ELF文件为例(这一系列的文章重点关注最本质的原理思想,所以这里讨论的同样适合Windows下的可执行文件即exe文件)。
在前几节中我们将可执行文件简单的划分为了两段,数据段和代码段,在这里我们继续丰富可执行文件中的内容,如图所示,在动态链接下,可执行文件当中会新增两段,即dynamic段以及GOT(Global offset table)段,这两段内容就是是我们之前所说的必要信息。

clipboard.png

dynamic段中保存了可执行文件依赖哪些动态库,动态链接符号表的位置以及重定位表的位置等信息。关于dynamic以及GOT段的作用限于篇幅就不重点阐述了。如果你对GOT段的具体作用很好奇的话,欢迎关注微信公共账号,码农的荒岛求生。
当加载可执行文件时,操作系统根据dynamic段中的信息即可找到使用的动态库,从而完成动态链接。

这里需要强调一点,在编译链接过程中,可以同时使用动态库以及静态库。这两种库的使用并不冲突,那么在这种情况下生成的可执行文件中,可执行文件中包含了静态库的数据和代码,以及动态库的必要信息。

至此,关于静态库,静态链接,动态库,动态链接就讲述到这,那么接下来的问题就是静态库和动态库都有什么样的优缺点。

动态库vs静态库

在计算机的历史当中,最开始程序只能静态链接,但是人们很快发现,静态链接生成的可执行文件存在磁盘空间浪费问题,因为对于每个程序都需要依赖的libc库,在静态链接下每个可执行文件当中都有一份libc代码和数据的拷贝,为解决该问题才提出动态库。

在前几节我们知道,动态链接下可执行文件当中仅仅保留动态库的必要信息,因此解决了静态链接下磁盘浪费问题。动态库的强大之处不仅仅于此,我们知道对于现代计算机系统,比如PC,通常会运行成百上千个程序(进程),且程序只有被加载到内存中才可以使用,如果使用静态链接那么在内存中就会有成百上千份同样的libc代码,这对于宝贵的内存资源同样是极大的浪费,而使用动态链接,内存中只需要有一份libc代码,所有的程序(进程)共享这一份代码,因此极大的节省了内存资源,这也是为什么动态库又叫共享库。

动态库还有另外一个强大之处,那就是如果我们修改了动态库的代码,我们只需要重新编译动态库就可以了而无需重新新编译我们自己的程序,因为可执行文件当中仅仅保留了动态库的必要信息,重新编译动态库后这些必要都信息是不会改变的(只要不修改动态库的名字和动态库导出的供可执行文件使用的函数),编译好新的动态库后只需要简单的替换原有动态库,下一次运行程序时就可以使用新的动态库了,因此动态库的这种特性极大的方便了程序升级和bug修复。我们平时使用都客户端程序,比如我们常用QQ,输入法,播放器,都利用了动态库的这一优点,原因就在于方便升级以bug修复,只需要更新相应的动态库就可以了。

动态库的优点不止于此,我们知道动态链接可以出现在运行时(run-time dynamic link),动态链接的这种特性可以用于扩展程序能力,那么如何扩展呢?你肯定听说过一样神器,没错,就是插件。你有没有想过插件是怎么实现的?实现插件时,我们只需要实现几个规定好的几个函数,我们的插件就可以运行了,可这是怎么做到的呢,答案就在于运行时动态链接,可以将插件以动态的都方式实现。我们知道使用运行时动态链接无需在编译链接期间告诉链接器所使用的动态库信息,可执行文件对此一无所知,只有当运行时才知道使用什么动态库,以及使用了动态库中哪些函数,但是在编译链接可执行文件时又怎么知道插件中定义了哪些函数呢,因此所有的插件实现函数必须都有一个统一的格式,程序在运行时需要加载所有插件(动态库),然后调用所有插件的入口函数(统一的格式),这样我们写的插件就可以被执行起来了。

动态库都强大优势还体现在多语言编程上。我们知道使用Python可以快速进行开发,但Python的性能无法同C/C++相比(因为Python是解释型语言,至于什么是解释型语言我会在后面码农的荒岛求生系列文章当中给大家详细讲解),有没有办法可以兼具Python的快速开发能力以及C/C++的高性能呢,答案是可以的,我们可以将C/C++代码编译链接成动态库,这样python就可以直接调用动态库中的函数了。不但Python,Perl以及Java等都可以通过动态库的形式调用C/C++代码。动态库的使用使得同一个项目不同语言混合编程成为可能,而且动态库的使用更大限度的实现了代码复用。

了解了动态库的这么多优点,那么动态库就没有缺点吗,当然是有的。

首先由于动态库是程序加载时或运行是才进行链接的,因此同静态链接相比,使用动态链接的程序在性能上要稍弱于静态链接,这时因为对于加载时动态链接,这无疑会减慢程序都启动速度,而对于运行时链接,当首次调用到动态库的函数时,程序会被暂停,当链接过程结束后才可以继续进行。且动态库中的代码是地址无关代码(Position-Idependent Code,PIC),之所以动态库中的代码是地址无关代码是因为动态库又被成为共享库,所有的程序都可以调用动态库中的代码,因此在使用动态库中的代码时程序要多做一些工作,这里我们不再具体展开讲解到底程序多做了哪些工作,对此感兴趣当同学可以参考CSAPP(深入理解计算机系统)。这里我们说动态链接的程序性能相比静态链接稍弱,但是这里的性能损失是微乎其微的,同动态库可以带来的好处相比,我们可以完全忽略这里的性能损失,同学们可以放心的使用动态库。

动态库的一个优点其实也是它的缺点,即动态链接下的可执行文件不可以被独立运行(这里讨论的是加载时动态链接,load-time dynamic link),换句话说就是,如果没有提供所依赖的动态库或者所提供的动态库版本和可执行文件所依赖的不兼容,程序是无法启动的。动态库的依赖问题会给程序的安装部署带来麻烦,在Linux环境下尤其严重,以笔者曾参与开发维护的一个虚拟桌面系统为例,我们在开发过程中依赖的一些比较有名的第三方库默认不会随着安装包发布,这就会导致用户在较低版本Linux中安装时经常会出现程序无法启动的问题,原因就在于我们编译链接使用都动态库和用户Linux系统中都动态库不兼容。解决这个问题的方法通常有两种,一个是用户升级系统中都动态库,另一个是我们讲需要都第三方库随安装包一起发布,当然这是在取得许可的情况下。

在了解了动态库的优缺点后,接下来我们来看一下静态库。

静态链接是最古老也是最简单的链接技术。静态链接都最大优点就是使用简单,编译好的可执行文件是完备的,即静态链接下的可执行文件不需要依赖任何其它的库,因为静态链接下,链接器将所有依赖的代码和数据都写入到了最终的可执行文件当中,这就消除了动态链接下的库依赖问题,没有了库都依赖问题就意味着程序都安装部署都得到了极大都简化。请大家不要小看这一点,这对当今那些拥有海量用户的后端系统来说至关重要,比如类似微信这种量级的系统,其后端会部署在成千上万台机器上,这么多的机器其系统的安装部署以及升级会给运维带来极大挑战,而静态链接下的可执行文件由于不依赖任何库,因为部署非常方便,仅仅用一个新的可执行文件进行覆盖就可以了,因此极大的简化了系统部署以及升级。笔者之前所在的某电商广告后端系统就完全使用静态链接来简化部署升级。

而静态库的缺点相信大家都已经清楚了,那就是静态链接会导致可执行文件过大,且多个程序静态链接同一个静态库的话会导致磁盘浪费的问题。

到这里关于静态库和动态库的讨论就告一段落了,相信大家对于这两种链接类型都有了清晰都认知。接下来让我们稍作休息,开始链接器的下一个重要功能,重定位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/186837.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 常见命令篇

history 获取执行的指令记录 语法格式: history [参数] 常用参数: -a 写入命令记录 -c 清空命令记录 -d 删除指定序号的命令记录 -n 读取命令记录 -r 读取命令记录到缓冲区 -s 将指定的命令添加到缓冲区 -w 将缓冲区信息写入到历史文件 history#获取最近的三条…

Python是个什么鬼?朋友靠它拿了5个offer

闺蜜乐乐,外院科班出身,手持专八和CATTI证书,没想到找工作时却碰了钉子… 半夜12点,乐乐跟我开启了吐槽模式: 拿到offer的都是小公司的翻译活儿,只能糊个口。稍微好点的平台要求可就多了,不仅语…

java计算下一个整10分钟时间点

最近工作上遇到需要固定在整10分钟一个周期调度某个任务,所以需要这样一个功能,记录下 package org.example;import com.google.gson.Gson; import org.apache.commons.lang3.time.DateUtils;import java.io.InputStream; import java.util.Calendar; i…

Hive内置表生成函数

Hive内置UDTF 1、UDF、UDAF、UDTF简介2、Hive内置UDTF 1、UDF、UDAF、UDTF简介 在Hive中,所有的运算符和用户定义函数,包括用户定义的和内置的,统称为UDF(User-Defined Functions)。如下图所示: UDF官方文档…

Springboot学生疫情管理系统-计算机毕设 附源码 25567

Springboot学生疫情管理系统的设计与实现 摘 要 随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理。在现实运用中,应用软件的工作规则和开发步骤&#xf…

Dubbo配置注册中心设置application的name使用驼峰命名法可能存在的隐藏启动异常问题

原创/朱季谦 首先,先提一个建议,在SpringBootDubbo项目中,Dubbo配置注册中心设置的application命名name的值,最好使用xxx-xxx-xxx这样格式的,避免随便使用驼峰命名。因为使用驼峰命名法,在Spring的IOC容器…

数据结构总复习

文章目录 线性表动态分配的顺序存储结构链式存储 线性表 动态分配的顺序存储结构 通过分析代码,我们发现,要注意什么: 要分清你的下标Insert 函数是可以用来没有元素的时候,增加元素的Init(或者Create )函数一般只用来分配空间…

Python中如何选择Web开发框架?

Python开发中Web框架可谓是百花齐放,各式各样的web框架层出不穷,那么对于需要进行Python开发的我们来说,如何选择web框架也就变成了一门学问了。本篇文章主要是介绍目前一些比较有特点受欢迎的Web框架,我们可以根据各个Web框架的特…

在线定制印刷系统源码/定制云印刷/个性印刷在线DIY定制商城系统/全站DIV+CSS 布局+手机、PC端

源码简介: 在线定制印刷系统源码/定制云印刷,它是个性印刷在线DIY定制商城系统,而且全站采用DIVCSS 布局,可以手机、PC端实时互通。 支持多种产品定制,包括但不限于水杯、雨伞、U盘、T恤、衬衫和四件套。独创的制作间…

Jenkins与Docker的自动化CI/CD流水线实践

Pipeline 有诸多优点,例如: 项目发布可视化,明确阶段,方便处理问题 一个Jenkins File文件管理整个项目生命周期 Jenkins File可以放到项目代码中版本管理 Jenkins管理界面 操作实例:Pipeline的简单使用 这里是比较…

电源控制系统架构(PCSA)之系统分区电压域

目录 4.1 电压域 4.1.1 系统逻辑 4.1.2 Always-On逻辑 4.1.3 处理器Clusters 4.1.4 图形处理器 4.1.5 其他功能 4.1.6 SoC分区示例 本章描述基于Arm组件的SoC划分为电压域和电源域。 所描述的选择并不详尽,只是可能性的一个子集。目的是描述基于Arm组件的SoC…

MySQL-04-InnoDB存储引擎锁和加锁分析

Latch一般称为闩锁(轻量级锁),因为其要求锁定的时间必须非常短。在InnoDB存储引擎中,latch又分为mutex(互斥量)和rwlock(读写锁)。 Lock的对象是事务,用来锁定的是…

实验题【网关设置+VRRP+静态路由+OSPF】(H3C模拟器)

嘿,这里是目录! ⭐ H3C模拟器资源链接1. 实验示意图2. 要求和考核目标3. 当前配置3.1 PC1、PC2、PC3、PC4和PC5配置3.2 SW配置3.2.1 SW2配置3.2.2 SW3配置3.2.3 SW4配置3.2.4 SW1配置 3.2. R配置3.2.1 R1配置3.2.2 R2配置 ⭐ H3C模拟器资源链接 H3C网络…

Windows下安装MySQL

几年前学习mycat中间件的时候在window机器上安装过MySql,但是由于电脑配置不高,同时打开Mysql服务,idea、SQlyog等软件非常卡,再加上SQLyog和MySQL版本不兼容导致登录不上,于是把它卸载了。最近做练习需要,…

Qt 软件调试(二)使用dump捕获崩溃信息

Qt应用程序异常崩溃该怎么办&#xff0c;生成dump文件再回溯分析&#xff0c;可以快速且准确的帮助我们定位到崩溃的点。那么&#xff0c;本章我们分享下如何在Qt中生成dump文件。 一、使用minudump捕获崩溃信息 #include <QCoreApplication> #include <QDir> #i…

用Python写一个浏览器集群框架

更多Python学习内容&#xff1a;ipengtao.com 在分布式爬虫和大规模数据采集的场景中&#xff0c;使用浏览器集群是一种有效的方式&#xff0c;可以提高数据采集的速度和效率。本文将介绍如何用Python编写一个简单但强大的浏览器集群框架&#xff0c;以应对需要使用多个浏览器实…

原生小程序图表

原生小程序使用图表 话不多说直接进入正题 官方文档: https://www.ucharts.cn/v2/#/ 下载文件 首先去gitee上把文件下载到自己的项目中 https://gitee.com/uCharts/uCharts 找到微信小程序和里面的组件 把里面src下的文件全部下载下来放入自己项目中 项目文件 新建文件…

使用Linux JumpServer堡垒机本地部署与远程访问

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 安装Jump server二. 本地访问jump server三. 安装 cpolar内网穿透软件四. 配…

【面试HOT200】滑动窗口篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于【CodeTopHot200】进行的&#xff0c;每个知识点的修正和深入主要参…

linux shell操作 - 05 IO 模型

文章目录 流IO模型阻塞IO非阻塞IOIO多路复用异步IO网络IO模型 流 可以进行IO&#xff08;input输入、output输出&#xff09;操作的内核对象&#xff1b;如文件、管道、socket…流的入口是fd (file descriptor)&#xff1b; IO模型 阻塞IO&#xff0c; 一直等待&#xff0c;…