自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(378)
  • 收藏
  • 关注

原创 一文解析数据结构是如何装入 CPU 寄存器的?

我们创建了一个长度为1G的数组,每个int 4字节,则这个数组的大小就是4GB,这显然是一个很庞大的数组。那么很显然这些数据存放在内存中,而且这些数据在不同的场景下有不同的大小,从数B、数KB到数百GB都有可能,与此同时,CPU内部的寄存器数量是固定的,容量也是极其有限的,那么CPU是如何利用有限的资源操作庞大的数据结构呢?对于其它复杂的数据结构也是同样的道理,无论多么复杂的数据,代码对其一次的操作都是很简单很微小的,这一微小的操作使用的基本元素都可以通过内存读写指令加载到寄存器,修改完后再写回内存。

2023-12-14 14:45:54 1199

原创 UDP分片与丢包,UDP真的比TCP高效吗?

根据 UDP 通信的有界性,在 buf 足够大的情况下,接收到的一定是一个完整的数据包,UDP 数据在下层的分片和组片问题由 IP 层来处理,提交到 UDP 传输层一定是一个完整的 UDP 包,那么 recvfrom(9000) 将返回 8000。对于一些多点通信的场景,如果采用有连接的 TCP,那么就需要和多个通信节点建立其双向连接,然后有时在 NAT 环境下,两个通信节点建立其直接的 TCP 连接不是一个容易的事情,在涉及 NAT 穿越的时候,UDP 协议的无连接性使得穿透成功率更高.

2023-12-13 19:47:05 1764

原创 一文讲解Linux驱动编程必备基础知识

驱动程序是专用于控制和管理特定硬件设备的软件,因此也被称作设备驱动程序。从操作系统的角度来看,它可以位于内核空间(以特权模式运行),也可以位于用户空间(具有较低的权限)。对于 Linux 驱动程序来说,其运行在内核空间,把硬件功能提供给用户程序。本篇文章主要介绍Linux驱动程序的一些基础知识。内核空间和用户空间的概念有点抽象,主要涉及内存的访问权限。内核是有特权的,而用户应用程序则是受限制的。内核驻留和运行的地址空间。内核内存受访问标志保护,只能由内核访问,用户应用程不能访问。

2023-12-12 16:46:38 1473

原创 聊聊跨进程共享内存的内部工作原理

值得注意的是,这个文件并非是磁盘上的文件,而只是在内存里的。在 Linux 系统的进程虚拟内存中,一个重要的特性就是不同进程的地址空间是隔离的。这个方案在传输的数据量较小的时候工作是很不错的。内核中它的主要逻辑有两个,一是调用 get_unused_fd_flags 申请一个没使用过的文件句柄,二是调用 shmem_file_setup 创建一个共享内存文件。但如果进程间想共享的数据特别大,比如说几个 GB,那如果使用网络 IO 方案的话,就会涉及到大量的内存拷贝的开销,导致比较低的程序性能。

2023-12-11 19:44:37 1119

原创 深入解析Linux内核网络-拥塞控制系列(二)

为Cubic算法中的极为重要的变量,cubic的核心函数的最终目的就是计算出cnt值,用来控制在拥塞避免状态阶段,何时才能增大拥塞窗口,具体实现是通过与struct tcp_sock中的snd_cwnd_cnt(snd_cwnd_cnt表示当前的拥塞窗口中已经发送,即经过对方ACK确认的数据段的个数)进行比较,决定是否增大拥塞窗口大小,可以认为cnt是增加一个单位cwnd需要的ACK数量。然后根据t与K的大小,即当前的t是否超过了到达饱和点的时间,对应的是Cubic函数图像的中心位置。

2023-12-09 16:53:13 1126

原创 一文讲解关于MCU启动原理的几个关键问题

后续的启动流程不赘述。对于一些小容量的MCU来说,比如Cortex-M3/M4,他们的芯片里有内置Flash,这个Flash的特点跟上面说的bootROM很像,是MCU可以直接通过地址总线去访问到的,不需要进行外设初始化的。当然,这些MCU内部也是有bootROM的,因此这些MCU一上电可以选择从bootROM中启动,也可以选择从内置Flash中启动,是通过外部引脚进行选择的,选择了谁,就把谁的起始地址映射到0地址处。M7内核芯片比较灵活了,改变了固定从0x0000 0000地址读取中断向量表的问题。

2023-12-08 17:41:59 732

原创 浅析CPU 空闲时在干嘛?

人空闲时会发呆会无聊,计算机呢?假设你正在用计算机浏览网页,当网页加载完成后你开始阅读,此时你没有移动鼠标,没有敲击键盘,也没有网络通信,那么你的计算机此时在干嘛?如果此时你正在计算机旁,并且安装有 Windows 或者 Linux ,你可以立刻看到自己的计算机 CPU 使用率是多少。这是一台安装有 Win10 的笔记本:可以看到大部分情况下 CPU 利用率很低,也就在 8% 左右,而且开启了 283 个进程,,就好比你写了一个打印用户输入的程序,如果用户一直不按键盘,那么你的进程就处于这种状态。

2023-12-07 16:47:12 1124

原创 解析操作系统是如何启动起来的?

加电CPU重置后开始在地址0xffff0处开始执行指令,这个地址其实是BIOS ROM的末尾处,该位置其实是一个跳转指令,跳转到ROM的一段启动代码上,该代码会进行必要的自检,Power-on self-test (POST),展示BIOS启动界面等等,最重要的一步是找到启动设备,所谓启动设备就是指从哪里加载操作系统,比如CD-ROM、或者磁盘、甚至U盘等都可以作为启动设备,早些年流行用U盘重新安装系统,其实就是告诉BIOS的这段代码从U盘中加载操作系统。

2023-12-06 14:40:14 980

原创 一文看懂 Linux 内核,清晰明了

这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。上面说的驱动在注册的时候会调用函数 bus_for_each_dev(), 对在每个挂在虚拟的platform bus 的设备作__driver_attach()→driver_probe_device(),在此函数中会对dev和drv做初步的匹配,调用的是drv->bus->match所指向的函数。

2023-12-05 14:45:13 1856

原创 深入解析Linux内核网络-拥塞控制系列(一)

没错,这是一种经典网络拥塞控制算法的基础理论,但在实际的实现时不同的拥塞控制算法,有很大差别。如果想安装特定的拥塞控制算法可以通过modprobe命令对指定的拥塞控制算法进行安装,如下所示安装了Vegas拥塞控制算法,此时再查看当前系统中可以使用的拥塞控制算法,多了一个Vegas算法。如果留意的话,在本文开始时提到了很多传统的拥塞控制算法,那么在上面的命令中没有看到,其实有众多拥塞控制算法在Linux中没有进行安装,如下命令。下面看一个特别重要的框架,也可以称为是拥塞控制引擎,如下结构体所示,

2023-12-04 15:17:01 1093

原创 深入计算机系统看性能优化

这里为了说明效果,我们编译的时候,并没有采用优化(编译优化,确实可以提高程序运行的效率,但是过高的编译优化等级会有一定的副作用,另外编译器优化也具有一定的局限性,高效的代码仍然应该是我们追求的目标)。我们知道这里的判断一直是0。这样的机器语言由纯粹的0和1构成,十分复杂,不方便阅读和修改,也容易产生错误。所以有些情况下,当我们根据实际的情况可以判断出哪条分支的可能性更高的时候,我们就可以站在上帝视角给予一定的提示,这样就可以降低分支预测错误,减少CPU的无用功了,从而可以有效的提高性能,同时也节省了功耗。

2023-12-02 16:26:34 1015

原创 一篇解析context_switch进程切换(针对ARM体系架构)

进程独有类型的 TLB:用户地址空间是每个进程独立的地址空间。从 prev 进程切换到next 进程时,TLB 中缓存的 prev 进程的相关数据对于 next 进程是无用的,因此可以刷新。是什么,它描述了一个进程切换时,CPU所需要保存的寄存器,也称为硬件上下文,ARM体系下的cpu_context保存了以下寄存器,将上次next进程保存的cpu_context的值。全局类型的 TLB:内核空间是所有进程共享的空间,因此这部分空间的虚拟地址到物园理地址的翻译是不会变化的,可以理解为全局的。

2023-12-01 15:58:50 1624

原创 嵌入式数据传输及存储的C语言实现

各种数据类型编程EEPROM,SPI Flash等存储器的简易方法,一般这些存储器都是字节编程,写入浮点等数据类型时不太方便。各种类型的数据传输和存储就涉及到大小端的问题,首先要简单说下芯片的大小端问题,这里主要讨论Cortex-M内核。各种数据类型的SPI,UART,I2C等传输问题。从机工程也定义一个同样的结构体变量,比如我们把接收到一帧数据存到缓冲。市面上其他厂家基本也都固化的小端格式。M内核支持大端或者小端,等方式来访问,非常方便。

2023-11-30 19:46:03 495

原创 一文例说嵌入式 C 程序的内聚和耦合

有些函数数在调用时,利用形式参数传地址的方式,在函数体内通过指针可以修改其指向的作用域以外的存储单元,这构成了更强的耦合,称为特征耦合,在这里,使函数之间产生联系的是地址这样的特征标识。现在将“找出完全平方数并输出”的功能仍放在main函数中(独立成为单独的函数也可以,但不必要了),而“每5个数据后换行”的功能,设计一个名称为format的函数,它每调用一次就输出一个空格作为两个完全平方数间的分隔,而每调用到第5次时,输出的是一个换行。对于这样的函数,如果不致于产生高耦合的话,可以分开两个函数实现。

2023-11-28 16:00:58 1195

原创 一文解析嵌入式linux构建之Yocto和buildroot

(1) 配置分成几个部分: Distribution 配置 (package配置,toolchain和libc选择...) Machine Configuration (定义架构, CPU功能, BSP) Image recipe (target安装什么package) Local配置 (Distribution和默认machine选择, 编译时使用多少个线程, 是否删除build artifact)支持ext2/3/4, ubifs, iso9600等,也支持VM镜像:vmdk,vdi,qcow2。

2023-11-27 17:22:04 2278 1

原创 一篇总结 Linux 系统启动的几个汇编指令

在一个完整的汇编程序中至少要有一个 ENTRY (也可以有多个,当有多个 ENTRY 时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个 ENTRY (可以没有)。其中,表达式的值用于指定对齐方式,可能的取值为2的幂,如 1 、2 、4 、8 、16 等。ARM 微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。

2023-11-24 17:32:16 1057

原创 一文聊聊近些年 CPU 在微架构、IO 速率上的演进过程

在 Intel 历年的 CPU 中,在 2013 年的 Haswell 采用的是 22 nm 的工艺。用光来对晶圆进行蚀刻。在新的单核架构中,CPU 中的各种缓存如 TLB、L1、L2变的越来越大,支持的超变量路数也再变多。另外就是内存的频率,即使是同一代际的内存,频率支持的也是越来越高。虽然制程不断提升到了 22nm、14nm、10nm、7nm、...,但是由于芯片功能的增加和性能的提升,功耗上取得的效果一直不能令人满意。CPU硬件一直在进步,在过去的很多年中,服务器端计算性能的提升都是靠硬件来提升的。

2023-11-23 14:24:05 189

原创 一文深入理解Linux进程间通信

什么是进程间通信?为什么要有进程间通信?为什么能进程间通信?我们先拿人来做个类比,人与人之间为什么要通信,有两个原因。首先是因为你有和对方沟通的需求,如果你都不想搭理对方,那就肯定不用通信了。其次是因为有空间隔离,如果你俩在一起,对方就站在你面前,你有话直说就行了,不需要通信。此时你非要给对方打个电话或者发个微信,是不是显得非常奇怪、莫名其妙。如果你俩不在一块,还有事需要沟通,此时就需要通信了。通信的方式有点烽火、送信鸽、写信、发电报、打电话、发微信等。采取什么样的通信方式跟你的需求、通信量的大小、以及客观

2023-11-22 16:39:59 167

原创 一文讲解eBPF helper 函数的设计与实现

相信在阅读本文后,您不仅能够轻松应对由于错误调用辅助函数导致的 eBPF verifier 问题,还能了解如何实现一个新的 eBPF 辅助函数。eBPF 辅助函数在开发 eBPF 程序中扮演着重要的角色,深入地了解 eBPF 辅助函数的设计和实现可以帮助解决开发过程中的许多相关问题。扩展类型是在基本类型的基础上,添加了空指针类型,表示返回值可能是空指针,那么 eBPF verifier 需要考虑针对空指针进行安全验证。扩展类型在基本类型的基础上,添加了空指针类型,即允许入参为空指针。

2023-11-21 15:24:42 488 1

原创 Linux内核调试篇——获取内核函数地址的四种方法(一文解决)

在内核调试中,经常需要知道某个函数的地址,或者根据函数地址找到对应的函数,从而进行更深一步的debug。命令是用于查看二进制文件(如可执行文件、目标文件、库)的符号表的工具,所以可以用。由于vmlinux比较大,如果要查找某个函数的地址,需要使用grep进行过滤。内核符号表是一个映射,它将内核代码段中的地址映射到对应的函数名或全局变量名。这会返回与指定函数名匹配的符号的地址、类型和名称。等工具来查看它的符号表,从而获取函数地址。反汇编出来,得到的反汇编文件就会包含。编译出来的内核映像文件,可以通过。

2023-11-20 16:47:13 892

原创 一文讲解关于嵌入式系统程序运行的几个问题

首先要清楚的是,CPU需要在存储器中读取指令,指令地址由PC寄存器给出,每执行完一条指令PC会自动的指向下一条指令,如果指令的长度不等会使得给出的地址不总是有一致的对齐,其次程序运行总会伴随跳转,这使得指令的寻址更具有随意性,所以说要直接在某种存储器中执行程序,至少读取数据时要能够任意寻址,而NOR Flash是刚好能满足要求的。不过有一类Flash存储器在读取数据时可以做到任意的寻址而不会有太大的花销,它的读操作是接近于RAM的,而写操作依然延续了按块擦除然后再按块写的特点,典型的如NOR Flash。

2023-11-16 14:53:49 167

原创 一文搞定以太网PHY、MAC及其通信接口

通常STA都是MAC层器件的一部分,而MMD则是PHY层器件的一部分。不论是物理连接的MII总线和 SMI 总线,还是 PHY 的状态寄存器和控制寄存器都是由IEEE的规范的。我们看到了,不论是物理连接的MII界面和SMI总线还是PHY的状态寄存器和控制寄存器都是有IEEE的规范的,因此不同公司的MAC和PHY一样可以协调工作。一是从MAC层到PHY层的发送数据接口,二是从PHY层到MAC层的接收数据接口,三是从PHY层到MAC层的状态指示信号,四是MAC层和PHY层之间传送控制和状态信息的MDIO接口。

2023-11-15 15:03:05 621

原创 嵌入式软件开发要注意这七种错误!

其实不只是新人——一些有几年工作经验的开发人员也会表现出这种傲慢,一部分原因是其满足于个人获得的专业成就,另一部分可能的原因是其缺乏和优秀的人共事的机会,有点坐井观天。虽然他们的态度和出发点是好的,但对整个团队造成的后果是灾难性的,浪费了很多的时间,导致团队得日夜赶工。是啊,能不急吗,排到后边,还需要解决代码冲突的问题。这句话在某种程度上是对的,但是你从事这项工作的年限,并不一定代表你获得了相同年限的工作经验,正如一句话所说:“我们以为我们是工作了十年,其实却只有一年的工作经验,只不过又重复用了九年”。

2023-11-14 14:05:59 458

原创 一篇揭秘Linux高性能服务epoll 的本质

一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题.执行epoll_create() 时,创建了红黑树和就绪链表;执行 epoll_ctl() 时,如果增加 socket 句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据;执行 epoll_wait() 时立刻返回准备就绪链表里的数据即可。ET模式(边缘触发)

2023-11-13 15:19:02 88

原创 万字详解Linux内核内存规整!超详细!

这里简单介绍⼀下watermark_boost_factor特性,当分配内存时如果在对应migrate type上没有分配到内存,那么系统将会从fall_back的migrate type进行内存分配,有时将其叫做”偷“,由于分配了不匹配迁移类型的内存,内核会认为这可能存在外部碎片的风险,所以当出现这种”偷“时内核会提前进行内存回收及规整,从而降低后续”偷“行为的发生,避免内存碎片问题,提升内存分配的效率,这就是watermark_boost_factor特性。

2023-11-11 14:47:20 303

原创 一文讲解Linux内核Makefile执行流程

如果还不熟悉Makefile语法,建议先系统的学习一下,特别是以下几点:(1) Makefile哪些部分包含的是shell语句:编译规则中的指令部分= XX中的XX部分$(if …, XX, XX)中的XX部分(2) 变量展开:=(延迟赋值)、:=(立即赋值)、!=(值为shell命令)、?=(条件赋值)、+=(追加)(3) include:将指定的其它Makefile内容,展开到当前Makefile-f/-C:嵌套执行指定(目录中的)Makefile。

2023-11-10 14:43:10 245

原创 一篇简述 Linux 移植与系统启动

4)/dev 存放设备文件的目录5)/etc 存放系统管理和配置文件的目录6)/home 用户主目录7)/lib 存放动态链接共享库的目录8)/sbin存放系统管理员使用的管理程序的目录9)/mnt 系统提供这个目录是让用户临时挂载其他的文件系统10)/proc 虚拟文件系统11)/usr 最庞大的目录12)/var某些大文件的溢出区13)/tmp 公用的临时文件存储点。但为了能使用zImage,必须在它的开头加上解压缩的代码,将zImage解压缩之后才能执行,因此它的执行速度比Image要慢。

2023-11-09 15:50:46 240

原创 一文解析嵌入式Linux系统自动构建框架

该目录下的配置文件记录着该机器平台或者方案使用的工具栏,boot, kernel,各种应用软件包的配置和是否编译选择的状态,之前所说的某个特殊开发板整个系统的配置文件,就在configs/目录下。你不用再为某某开源软件如何移植到我的Linux 开发板而到处在QQ群和论坛问人了,哪怕以后还要你自己开发的新的软件包,所有繁琐的移植工作,只要做了一次,都可以用Makefile写成自动构建脚本,移植工作做了一次,就不用做第二次了,交给Buildroot自动来做就可以了。d). 团队协作的利器。

2023-11-08 17:43:40 248

原创 一文深入搞懂ARM处理器架构

A32架构的ARM的地址总线为32位,故CPU可寻址范围为0x00000000~0xffffffff寻址空间为4GB,所有的内部和外部存储或者外设单元都需要通过对应的地址来操作,不同芯片外设的种类数量寻址空间都不一样,为了能让内核更方便的管理不同的芯片设计,ARM内核会先给出预定义的存储映射。不过需要注意的是由于修改的CPSR是该模式下的影子CPSR,即SPSR,因此并不是实际的CPSR,所以一般的做法是修改影子CPSR,然后执行一个MOVS指令来恢复执行某个断点并切换到新模式。每条指令都采用标准字长。

2023-11-07 14:16:09 23497

原创 带你一文搞懂 Linux 网络 Phy 驱动

phy_device 的状态怎么传递给 net_device,让其在 link 状态变化时做出对应的配置改变,这个任务就落在上述的 struct phylink 中介身上。每个 phy 芯片会创建一个 struct phy_device 类型的设备,对应的有 struct phy_driver 类型的驱动,这两者实际上是挂载在 mdio_bus_type 总线上的,mac 会被注册成 struct net_device。下面就以 fec 网口驱动为例,展示一下网卡 fec 和 phy 的协作过程。

2023-11-06 16:21:18 823

原创 一文让你彻底明白,理解I/O多路复用

实际上文件描述符集合的变化频率比较低,select和poll频繁的拷贝整个集合,内核都快被烦死了,epoll通过引入epoll_ctl很体贴的做到了只操作那些有变化的文件描述符,同时epoll和内核还成为了好朋友,共享了同一块内存,这块内存中保存的就是那些已经可读或者可写的的文件描述符集合,这样就减少了内核和程序的拷贝开销。,比如文件在磁盘的什么位置、加载到内存中又是怎样管理的等等,这些信息统统交由操作系统打理,进程无需关心,操作系统只需要给进程一个文件描述符就足够了。第三个文件描述符可以读写了吗?

2023-11-04 14:56:24 124

原创 18张图揭秘高性能Linux服务器内存池技术是如何实现的

有的同学可能会说这还不简单,不就是一个指针到另一个指针的映射吗,直接用map之类存起来就好了,但问题并没有这么简单,原因就在于如果我们切分的内存块很小,那么会存在大量内存块,这就需要存储大量的映射关系,有没有办法改进呢?注意,虽然这里给出了线程局部存储的设计,但并不是说加锁的方案就比不上线程局部存储方案,还是那句话,一切要看使用场景,如果加锁的方案够用,那么我们就没有必要绞尽脑汁的去用其它方案,因为加锁的方案更简单,代码也更容易维护。也就是说,通过内存池,一次内存的申请再也不用去绕一大圈了。

2023-11-03 14:18:15 121

原创 C语言映射表在串口数据解析中的应用

4、按下Up按键 跳转到指定场景current_stage的值根据映射表改变。3、定义两个变量保存当前场景和上一个场景。2、指令、函数映射表。3、串口解析函数实现。

2023-11-02 14:37:06 215

原创 一文深入了解 CPU 的型号、代际架构与微架构

这里面包含的含义就是,这是一个Intel 的酷睿子品牌的 CPU,i7代表着中高端,代际编号是7,这个代际的处理器架构是 2016 年发布的采用的 Kaby Lake 架构生产的。制程工艺的进步带来的好处主要是能效比的提升,单位面积上晶体管的数量增加了,但是需要的能耗却变低了。当前 CPU 能支持什么样规格的内存,以及能支持多大的内存,都是由 CPU 中的内存控制器来决定的。不同的微架构对核的设计是不同的,比如 TLB、L1、L2 等各种缓存,再比如 CPU 核内部的运算单元都会有所不同。

2023-11-01 20:31:39 902

原创 全方位 Linux 性能调优经验总结

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。进程只有在调度到CPU上运行时才需要切换上下文,有以下几种场景:CPU时间片轮流分配,系统资源不足导致进程挂起,进程通过sleep函数主动挂起,高优先级进程抢占时间片,硬件中断时CPU上的进程被挂起转而执行内核中的中断服务。因此相比系统调用来说,在保存当前进程的内核状态和CPU寄存器之前,需要先把该进程的虚拟内存,栈保存下来。说明不是工具的问题。

2023-10-31 17:41:34 236

原创 一文分享提升嵌入式代码的分析工具

静态代码分析器能够设置严格的类型检查,将Var1=Var2因不同类型间的赋值而置为高亮,以及检查出其它不符合开发者本意的问题。有很多的方法能分析和确定堆栈的最坏情况下的的使用状态,但可以用静态代码分析器来找找合理使用堆栈的感觉。代码静态分析工具,顾名思义就是对代码进行静待分析,以提前预判(分析出)代码潜在的一些问题的工具。静态代码分析器广为人知的用途之一就是扫描软件中潜在的问题和漏洞。静态代码分析器的使用可以大大提高代码的质量和鲁棒性,如果设置得当,甚至可以确保代码与常见的或自定义的编码标准的一致性。

2023-10-30 16:02:45 293

原创 Linux内核代码中常用的数据结构

Linux内核实现了一套纯链表的封装,链表节点数据结构只有指针区而没有数据区,另外还封装了各种操作函数,如创建节点函数、插入节点函数、删除节点函数、遍历节点函数等。如图所示,单向链表具有单向移动性,也就是只能访问当前的节点的后继节点,而无法访问当前节点的前继节点,因此在实际项目中运用得比较少。如图所示,双向链表和单向链表的区别是指针区包含了两个指针,一个指向前继节点,另一个指向后继节点,如下代码所示。单向链表的指针区只包含一个指向下一个节点的指针,因此会形成一个单一方向的链表,如下代码所示。

2023-10-26 14:43:24 622

原创 一个进程最多可以创建多少个线程

话不多说,先来张脑图~linux 虚拟内存知识回顾32 位系统,用户态的虚拟空间只有 3G,默认创建线程时分配的栈空间是 8M,那么一个进程最多只能创建 380 个左右的线程。64 位系统,用户态的虚拟空间大到有 128T,理论上不会受虚拟内存大小的限制,而会受系统的参数或性能限制。

2023-10-25 15:41:53 142

原创 一文彻底理解C语言中的指针

指针这个概念首次出现在 PL/I 语言中,当时是为了增加链表处理能力,大家不要以为链表这种数据结构是非常司空见惯的,这在1964年左右并不是一件容易的事情,值得一提的是,Multics操作系统就是 PL/I 语言实现的,这也是第一个用高级语言实现的操作系统,然而Multics操作系统在商业上并不成功,参与该项目的Ken Thompson, Dennis Ritchie后来决定自己写一个更简单的,Unix以及C语言诞生了,或许是在开发Multic时见识到了PL/I语言中指针的威力,C语言中也有指针的概念。

2023-10-24 15:27:59 80

原创 Linux 后台开发必知的 I/O 优化知识总结

IO性能对于一个系统的影响是至关重要的。一个系统经过多项优化以后,瓶颈往往落在数据库;而数据库经过多种优化以后,瓶颈最终会落到IO。而IO性能的发展,明显落后于CPU的发展。Memchached也好,NoSql也好,这些流行技术的背后都在直接或者间接地回避IO瓶颈,从而提高系统性能。IO系统的分层:上图层次比较多,但总的就是三部分。磁盘(存储)、VM(卷管理)和文件系统。专有名词不好理解,打个比方说:磁盘就相当于一块待用的空地;LVM相当于空地上的围墙(把空地划分成多个部分);

2023-10-23 15:20:16 232

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除