当前位置:首页>Linux>拆解Linux共享内存原理:“零拷贝”通信的核心机制

拆解Linux共享内存原理:“零拷贝”通信的核心机制

  • 2026-02-27 03:33:37
拆解Linux共享内存原理:“零拷贝”通信的核心机制

在Linux系统进程通信的多元方案中,共享内存以“零拷贝”这一核心优势,成为高吞吐、低延迟场景的最优解之一,其底层机制直接决定了进程间数据交互的性能上限。传统进程通信(如管道、消息队列)需经历“用户态→内核态→用户态”的多次上下文切换,数据还需在用户缓冲区与内核缓冲区之间反复拷贝,这一过程不仅占用大量CPU资源,还会显著增加通信延迟。

而共享内存的核心突破在于,通过内核层面的内存映射机制,让多个进程直接访问同一块物理内存区域,实现数据的“直接共享”,彻底省去了冗余的数据拷贝步骤,这便是“零拷贝”通信的本质所在。深入拆解Linux共享内存的原理,不仅能厘清内核对共享内存段的创建、映射、权限管控等关键流程,更能深刻理解其为何能在数据库、分布式系统等高性能场景中成为通信基石。本文将从底层逻辑出发,逐层拆解共享内存的实现机制,揭开“零拷贝”通信高效运作的核心奥秘。

一、Linux 内存管理基础回顾

1.1虚拟内存与物理内存

在 Linux 内存管理的大框架下,虚拟内存和物理内存是两个基石概念 。虚拟内存是操作系统为每个进程精心打造的 “专属空间”,它就像是给进程提供了一个巨大且连续的地址空间。在 32 位系统中,虚拟地址空间大小固定为 4GB,进程仿佛拥有了这 4GB 的完整连续内存,可自由地进行内存分配与访问操作。这对于程序开发者而言,无疑极大地简化了内存管理的复杂度,无需再为物理内存的零散分布而烦恼。

从本质上讲,虚拟内存是对物理内存的一种巧妙抽象,它成功地将程序与物理内存的具体细节隔离开来。以进程 A 和进程 B 为例,它们各自拥有独立的 4GB 虚拟地址空间,在进程 A 看来,自己对内存地址 0x1000 的访问是独一无二的,完全感知不到进程 B 的存在,反之亦然。这种独立性和隔离性,确保了进程之间不会相互干扰,极大地提升了系统的稳定性和安全性。而物理内存,则是实实在在存在于计算机硬件中的内存,像我们常见的内存条就是物理内存的载体。它直接与 CPU 相连,负责存储正在运行的程序和数据。当 CPU 需要读取或写入数据时,会直接与物理内存进行交互,物理内存的读写速度极快,能为 CPU 提供高效的数据支持。

那么,虚拟内存与物理内存是如何建立联系的呢?这就不得不提到页表(Page Table)这一关键数据结构。页表就像是一本精确的 “地址字典”,详细记录了虚拟地址与物理地址之间的映射关系。当进程访问虚拟地址时,CPU 会借助内存管理单元(MMU),依据页表将虚拟地址精准地转换为物理地址,进而实现对物理内存的访问。假设进程访问虚拟地址 0x2000,MMU 查询页表后发现,该虚拟地址对应的物理地址是 0x8000,于是 CPU 便会去物理地址 0x8000 处读取数据。如果所需数据不在物理内存中,就会触发缺页中断,操作系统会迅速从磁盘中将数据加载到物理内存,并及时更新页表,以确保后续访问的顺畅。 页表的存在,巧妙地解决了虚拟地址与物理地址的映射难题,让虚拟内存得以高效运行。

(1)内存分页

内存分页是 Linux 内存管理的核心机制之一,它将虚拟内存和物理内存都划分为固定大小的页(Page) ,通常页的大小为 4KB。页表则是记录虚拟页到物理页映射关系的数据结构,它就像是一本地址字典,MMU 通过查询页表来实现虚拟地址到物理地址的转换 。

当 CPU 需要访问内存时,它会先根据虚拟地址计算出页号和页内偏移 。然后,CPU 会利用页号在页表中查找对应的物理页框号 。如果页表中存在这个映射关系,CPU 就可以通过物理页框号和页内偏移计算出实际的物理地址,从而访问到物理内存中的数据 。这个过程虽然听起来复杂,但对于 CPU 来说,它可以在极短的时间内完成,保证了程序的高效运行 。

举个例子,假设我们有一个进程需要访问虚拟地址 0x12345678,页的大小为 4KB(即 0x1000)。那么,通过计算可以得到页号为 0x12345(0x12345678 除以 0x1000 的商),页内偏移为 0x678(0x12345678 除以 0x1000 的余数) 。CPU 会根据页号 0x12345 在页表中查找对应的物理页框号,假设找到的物理页框号为 0x98765 ,那么最终的物理地址就是 0x98765678(0x98765 乘以 0x1000 再加上 0x678) 。内存分页机制大大提高了内存管理的效率和灵活性,减少了内存碎片的产生 。

(2)内存分配与回收

进程在运行过程中,需要向操作系统请求分配内存来存储数据和代码 。在 Linux 中,进程可以通过调用系统调用(如malloc、mmap等)来申请内存 。当进程调用malloc时,C 库会向内核发起brk或mmap系统调用,内核会根据进程的需求和当前内存的使用情况,为进程分配合适的内存空间 。

操作系统通过维护一些数据结构(如空闲内存链表、内存分配位图等)来管理内存资源 。当有新的内存请求时,操作系统会从空闲内存链表中寻找合适的内存块分配给进程 。如果没有足够大的连续空闲内存块,操作系统可能会进行内存碎片整理,或者从磁盘交换区(Swap)中换入一些内存页面,以满足进程的需求 。

当进程不再需要某些内存时,它需要及时释放这些内存,以便操作系统能够回收并重新分配给其他进程使用 。进程可以通过调用free函数来释放通过malloc分配的内存,或者通过munmap函数来释放通过mmap映射的内存 。操作系统在回收内存时,会将释放的内存块重新加入到空闲内存链表中,并更新相关的数据结构 。内存分配与回收的有序流转,确保了系统内存资源的高效利用 。

1.2进程地址空间布局

进程地址空间就像是一个精心规划的 “内存城市”,各个区域分工明确,协同工作,保障进程的正常运行。它主要包含以下几个重要部分:

  1. 代码段(Text Segment):这是程序中可执行代码的专属 “栖息地”,存放着 CPU 执行的机器指令。代码段具有共享和只读的特性,这意味着多个进程可以同时共享同一代码段,避免了重复加载带来的资源浪费。例如,系统中的常用库函数,多个进程都可能调用,通过共享代码段,只需在内存中加载一次即可。同时,只读属性也确保了代码的安全性,防止其他程序意外修改代码,保障了程序执行的稳定性。
  2. 数据段(Data Segment):用于存储已初始化的全局变量和静态变量。这些变量在程序运行期间始终存在,为程序提供了稳定的数据支持。比如一个全局变量int globalVar = 10;,它就存储在数据段中,在程序的任何地方都可以访问和修改它的值 。
  3. BSS 段(Block Started by Symbol):主要存放未初始化的全局变量和静态变量。与数据段不同,BSS 段在程序加载时并不占用实际的磁盘空间,而是在运行时才为这些变量分配内存。例如int uninitGlobalVar;这个未初始化的全局变量就位于 BSS 段,这样的设计有效地节省了磁盘空间和程序加载时间。
  4. 堆(Heap):是进程进行动态内存分配的区域,当程序运行过程中需要动态分配内存时,比如使用malloc、new等函数,就会从堆中申请内存。堆的大小是动态变化的,随着内存的分配和释放而伸缩。堆的管理相对复杂,需要合理地分配和回收内存,以避免内存泄漏和内存碎片等问题。
  5. 栈(Stack):用于存储函数的参数、局部变量以及函数调用的返回地址等。当函数被调用时,其参数和局部变量会被压入栈中,函数执行完毕后,这些数据会从栈中弹出。栈的生长方向是从高地址向低地址,它的操作速度非常快,因为栈的管理遵循简单的后进先出(LIFO)原则。
  6. 共享内存区域(Shared Memory Region):这是一个特殊的区域,允许多个进程共享同一块物理内存。通过共享内存,进程之间可以高效地进行数据通信和共享,极大地提高了数据传输效率,减少了数据拷贝带来的开销。例如,在数据库系统中,多个进程可能需要共享数据库的缓存数据,通过共享内存区域,这些进程可以直接访问和修改共享数据,实现高效的数据交互 。

这些不同区域在进程地址空间中各司其职,共同构成了一个有机的整体,为进程的正常运行提供了坚实的保障。

二、Linux共享内存原理

2.1什么共享内存

共享内存是 Linux 进程间通信(IPC,Inter - Process Communication)中一种极为高效的方式,它允许多个进程直接访问同一块物理内存区域 。这就好比多个办公室的工作人员可以直接进入同一个资料室,无需通过繁琐的文件传递流程,就能获取和修改资料,大大提高了信息交互的效率。在传统的进程间通信方式中,如管道(Pipe)和消息队列(Message Queue),数据往往需要在进程之间进行多次拷贝,这不仅耗费时间,还占用大量系统资源。而共享内存则打破了这种繁琐的模式,让多个进程能够直接在同一块内存中进行数据的读写操作 。

从内存管理的角度来看,共享内存的实现依赖于操作系统的虚拟内存机制。操作系统会为每个进程分配独立的虚拟地址空间,但通过巧妙的页表映射,不同进程的虚拟地址可以指向同一块物理内存。例如,进程 A 和进程 B 通过共享内存进行通信,操作系统会将共享内存区域映射到它们各自的虚拟地址空间中。当进程 A 向共享内存写入数据时,进程 B 可以立即看到这些数据的变化,反之亦然,因为它们实际上操作的是同一块物理内存 。这种直接的内存访问方式,避免了数据在进程间的多次拷贝,极大地提高了数据传输效率,使得共享内存在需要频繁进行大数据量传输的场景中表现尤为出色,如数据库系统中的数据缓存、图形处理中的图像数据共享等。

2.2共享内存相关系统调用

在 Linux 系统中,共享内存的使用离不开一系列系统调用,这些系统调用为开发者提供了创建、映射、控制和删除共享内存的能力。下面我们来详细介绍这些系统调用:

(1)shmget 函数:创建或获取共享内存标识符

#include <sys/ipc.h>#include <sys/shm.h>intshmget(key_t key, size_t size, int shmflg);

shmget函数用于创建一个新的共享内存段,或者获取一个已存在的共享内存段的标识符。它的参数如下:

  1. key:是一个key_t类型的键值,用于唯一标识共享内存段。不同进程可以通过相同的key来访问同一块共享内存。例如,在一个多进程协作的服务器程序中,各个进程可以约定使用同一个key值,如1234,来创建或获取共享内存,从而实现数据共享 。可以通过ftok函数根据文件路径和项目 ID 生成一个唯一的key值,确保不同进程能准确找到同一块共享内存。
  2. size:指定所需共享内存的大小,单位是字节。例如,如果要创建一个用于存储 1024 个整数的共享内存段,假设每个整数占 4 字节,那么size就应该设置为1024 * 4 。
  3. shmflg:是一组标志位,用于控制共享内存的创建和访问权限。常用的标志有IPC_CREAT,如果共享内存不存在,则创建一个新的共享内存;IPC_EXCL,通常与IPC_CREAT一起使用,如果共享内存已存在,则返回错误,这样可以确保创建的是一个全新的共享内存 。权限标志与文件权限类似,如0666表示可读可写权限。 如果shmget函数调用成功,会返回一个非负整数,即共享内存标识符(shmid),后续对共享内存的操作都将使用这个标识符;如果失败,返回-1,并设置errno来指示错误原因,比如EINVAL表示参数无效,EEXIST表示共享内存已存在但IPC_EXCL被设置等 。

(2)shmat 函数:将共享内存映射到进程的虚拟地址空间

#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, constvoid *shmaddr, int shmflg);

shmat函数用于将shmget返回的共享内存标识符shmid所代表的共享内存段映射到当前进程的虚拟地址空间中,使其可被进程访问。参数含义如下:

  1. shmid:是shmget函数返回的共享内存标识符,通过这个标识符,系统可以找到对应的共享内存段。
  2. shmaddr:指定共享内存映射到进程虚拟地址空间的地址。通常设为NULL,表示由系统自动选择合适的地址进行映射。例如:
void *shared_mem = shmat(shmid, NULL0);if (shared_mem == (void *)-1) {    perror("shmat failed");    exit(EXIT_FAILURE);}

如果手动指定地址,需要确保该地址是合适的,并且满足内存对齐等要求,否则可能导致映射失败。

shmflg:是一组按位标志,SHM_RDONLY使附加的内存为只读,默认情况下不设置此标志,共享内存是可读可写的。SHM_RND用于控制共享内存附加的地址,如果shmaddr不为NULL且设置了SHM_RND,则共享内存将被映射到shmaddr向下调整为SHMLBA(系统页面大小的整数倍)的地址 。 成功调用shmat后,返回一个指向共享内存起始地址的指针,进程可以通过这个指针直接访问共享内存;如果失败,返回(void *)-1,并设置errno,例如EACCES表示权限不足,无法映射共享内存 。

(3)shmdt 函数:取消共享内存与进程虚拟地址空间关联

#include <sys/types.h>#include <sys/shm.h>intshmdt(constvoid *shmaddr);

shmdt函数用于将共享内存从当前进程的虚拟地址空间中分离,即取消进程对共享内存的映射。它的参数shmaddr是shmat函数返回的共享内存地址。例如:

int ret = shmdt(shared_mem);if (ret == -1) {    perror("shmdt failed");    exit(EXIT_FAILURE);}

调用shmdt后,进程不再能够通过原来的指针访问共享内存,但共享内存本身并不会被删除,只是减少了一个对它的引用 。如果此时还有其他进程在使用该共享内存,共享内存将继续存在,直到所有进程都调用shmdt分离共享内存,并且调用shmctl删除共享内存,共享内存才会被真正释放。如果shmdt函数执行成功,返回0;失败返回-1,并设置errno,如EINVAL表示无效的共享内存地址 。

(4)shmctl 函数:对共享内存进行控制操作

#include <sys/ipc.h>#include <sys/shm.h>intshmctl(int shmid, int cmd, struct shmid_ds *buf);

shmctl函数提供了对共享内存的各种控制操作。参数如下:

  1. shmid:共享内存标识符,用于指定要操作的共享内存。
  2. cmd:是一个命令参数,用于指定具体的控制操作。常用的命令有IPC_STAT,用于获取共享内存的当前状态信息,如大小、访问权限、创建时间等,并将这些信息存储在buf指向的shmid_ds结构体中;IPC_SET,用于设置共享内存的属性,前提是进程具有足够的权限,可设置的属性包括所有者 ID、组 ID、访问权限等;IPC_RMID,用于删除共享内存段,一旦调用IPC_RMID,共享内存将被标记为删除,当所有进程都与之分离后,共享内存将被真正释放 。
  3. buf:是一个指向shmid_ds结构体的指针,用于存储或传递共享内存的相关信息。在使用IPC_STAT时,buf用于接收共享内存的状态信息;在使用IPC_SET时,buf中包含要设置的新属性值;在使用IPC_RMID时,buf可以为NULL 。 shmctl函数执行成功返回0,失败返回-1,并设置errno,如EACCES表示权限不足,无法执行相应的控制操作,EINVAL表示无效的共享内存标识符或命令 。

2.3共享内存实现机制

在内核层面,共享内存的管理依赖于一系列复杂的数据结构和机制,其中struct shmid_kernel和struct mm_struct起着关键作用。struct shmid_kernel是内核中用于描述共享内存段的数据结构,它包含了共享内存的各种属性和状态信息 :

struct shmid_kernel {    struct kern_ipc_perm shm_perm;  // 权限和基本信息,如所有者、组、访问权限等    struct file *shm_file;         // 关联的伪文件,用于实现共享内存的映射和管理    unsigned long shm_nattch;      // 当前附加(映射)到该共享内存的进程数    unsigned long shm_segsz;       // 段大小(字节)    time_t shm_atim;               // 最后访问时间    time_t shm_dtim;               // 最后分离时间    time_t shm_ctim;               // 最后改变时间    struct pid *shm_cprid;         // 创建者PID    struct pid *shm_lprid;         // 最后操作PID    // ...其他字段...};

当创建一个共享内存段时,内核会分配一个struct shmid_kernel结构体,并初始化其中的字段。shm_perm字段记录了共享内存的权限和所有者等信息,确保只有授权的进程能够访问和操作共享内存 。shm_file关联的伪文件则为共享内存的映射提供了基础,通过文件系统的机制,实现共享内存与进程虚拟地址空间的映射 。shm_nattch字段用于记录当前有多少个进程正在使用该共享内存,这对于共享内存的生命周期管理至关重要,只有当所有进程都与之分离(shm_nattch为 0)时,共享内存才会被真正释放 。

struct mm_struct则是内核中用于管理进程内存映射的数据结构,每个进程都有一个对应的mm_struct 。当进程通过shmat函数将共享内存映射到自己的虚拟地址空间时,内核会在该进程的mm_struct中创建一个新的内存映射项,将共享内存的物理地址与进程的虚拟地址建立关联 。这个映射关系通过页表来维护,页表是虚拟内存与物理内存之间的映射表,它记录了每个虚拟页面所对应的物理页面 。在共享内存的场景下,不同进程的页表会将相同的物理内存页面映射到各自不同的虚拟地址空间,从而实现多个进程对同一块物理内存的共享 。

例如,假设有进程 A 和进程 B 共享一块内存。当进程 A 调用shmget创建共享内存时,内核创建struct shmid_kernel结构体并初始化。然后进程 A 调用shmat,内核在进程 A 的mm_struct中创建映射项,更新页表,将共享内存物理地址与进程 A 虚拟地址关联 。当进程 B 也调用shmat时,内核同样在进程 B 的mm_struct中创建映射项,使得进程 B 的虚拟地址也能访问到这块共享内存的物理地址 。这样,进程 A 和进程 B 就可以通过各自的虚拟地址对同一块共享内存进行读写操作,实现高效的数据共享和通信 。

三、零拷贝通信核心机制

3.1什么是零拷贝

零拷贝是一种在数据传输过程中,避免数据在用户空间与内核空间之间多次拷贝的技术 。在传统的数据传输方式中,数据往往需要从磁盘读取到内核缓冲区,再拷贝到用户空间缓冲区,之后又从用户空间缓冲区拷贝回内核空间的套接字缓冲区,最后发送到网络,这个过程涉及多次数据拷贝和上下文切换,消耗大量的 CPU 资源和时间 。

以文件传输为例,传统方式下,当我们要将一个文件通过网络发送出去时,首先要调用read系统调用,将文件数据从磁盘读取到内核缓冲区,然后再将内核缓冲区的数据拷贝到用户空间的应用程序缓冲区,接着应用程序调用write系统调用,把数据从用户空间缓冲区拷贝到内核空间的套接字缓冲区,最后由内核将套接字缓冲区的数据发送到网络 。每一次数据拷贝都需要 CPU 参与,并且数据在内存中多次移动,占用内存带宽。

而零拷贝技术则打破了这种繁琐的流程,它通过让数据直接在内核空间完成传输,避免了数据在用户空间的拷贝,从而极大地减少了 CPU 开销和数据传输时间 。在使用sendfile系统调用实现零拷贝时,数据可以直接从磁盘的内核缓冲区传输到网络套接字缓冲区,无需经过用户空间,这样不仅减少了数据拷贝次数,还减少了上下文切换次数,提高了数据传输效率 。零拷贝技术就像是搭建了一条数据高速公路,让数据能够快速、高效地从源头到达目的地,在大数据传输、高性能网络服务器等场景中发挥着重要作用 。

3.2零拷贝实现方式

在 Linux 系统中,零拷贝技术有多种实现方式,每种方式都有其独特的原理和适用场景。下面我们详细介绍几种常见的零拷贝实现方式。

(1)第一种实现方式:mmap + write

mmap是一种内存映射文件的方法,它将文件直接映射到进程的地址空间,使得进程可以像访问内存一样访问文件 。结合write系统调用,mmap + write实现了一种零拷贝的数据传输方式 。 当使用mmap时,通过mmap系统调用将文件映射到进程的虚拟地址空间,文件的内容直接与进程的内存建立映射关系 。

此时,DMA(直接内存访问)硬件将磁盘数据直接拷贝到内核缓冲区,然后内核将该缓冲区与进程的虚拟地址空间进行映射,进程可以直接通过指针访问文件数据,而无需将数据从内核缓冲区拷贝到用户空间缓冲区 。 之后,当需要将数据发送到网络时,调用write系统调用,数据直接从内核缓冲区拷贝到套接字缓冲区,最后由网络设备发送出去 。这个过程中,数据在用户空间没有进行拷贝,减少了一次数据拷贝的开销 。 下面是一个简单的代码示例,展示了如何使用mmap + write实现零拷贝:

#include <sys/mman.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#define FILE_NAME "test.txt"#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8888intmain(){    int file_fd, socket_fd;    struct stat file_stat;    char *file_data;    struct sockaddr_in server_addr;    // 打开文件    file_fd = open(FILE_NAME, O_RDONLY);    if (file_fd == -1) {        perror("open file failed");        exit(EXIT_FAILURE);    }    // 获取文件状态    if (fstat(file_fd, &file_stat) == -1) {        perror("fstat failed");        close(file_fd);        exit(EXIT_FAILURE);    }    // 使用mmap将文件映射到内存    file_data = (char *)mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, file_fd, 0);    if (file_data == MAP_FAILED) {        perror("mmap failed");        close(file_fd);        exit(EXIT_FAILURE);    }    // 创建套接字    socket_fd = socket(AF_INET, SOCK_STREAM, 0);    if (socket_fd == -1) {        perror("socket failed");        munmap(file_data, file_stat.st_size);        close(file_fd);        exit(EXIT_FAILURE);    }    // 设置服务器地址    memset(&server_addr, 0sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(SERVER_PORT);    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);    // 连接服务器    if (connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {        perror("connect failed");        munmap(file_data, file_stat.st_size);        close(file_fd);        close(socket_fd);        exit(EXIT_FAILURE);    }    // 使用write发送数据    if (write(socket_fd, file_data, file_stat.st_size) == -1) {        perror("write failed");    }    // 清理资源    munmap(file_data, file_stat.st_size);    close(file_fd);    close(socket_fd);    return 0;}

在这个示例中,首先使用open打开文件,然后通过fstat获取文件状态,接着使用mmap将文件映射到内存,之后创建套接字并连接到服务器,最后使用write将映射的内存数据发送到服务器 。整个过程中,数据在用户空间没有进行拷贝,提高了数据传输效率 。

(2)第二种实现方式:sendfile

sendfile是 Linux 系统提供的一个系统调用,专门用于在两个文件描述符之间直接传输数据,通常用于将文件内容发送到网络套接字 。它的出现,使得数据可以在内核空间直接完成传输,无需用户空间的参与,从而实现了高效的零拷贝 。 sendfile的工作原理是,当调用sendfile时,内核首先根据输入文件描述符,将文件数据从磁盘读取到内核缓冲区(通过 DMA) 。然后,内核直接将内核缓冲区中的数据传输到输出文件描述符对应的套接字缓冲区(如果网卡支持 SG - DMA 技术,甚至可以直接将数据从内核缓冲区传输到网卡设备内存,避免了在内核缓冲区与套接字缓冲区之间的一次拷贝) 。

在整个过程中,数据完全在内核空间流动,没有经过用户空间,减少了数据拷贝次数和上下文切换次数 。 在网络传输场景中,sendfile的优势尤为明显 。以 Web 服务器为例,当服务器需要将静态文件(如 HTML、CSS、图片等)发送给客户端时,使用sendfile可以大大提高传输效率 。传统方式下,需要先使用read将文件数据从磁盘读取到用户空间缓冲区,再使用write将数据从用户空间缓冲区写入套接字,这个过程涉及多次数据拷贝和上下文切换 。而使用sendfile,只需要一次系统调用,内核就能直接将文件数据从磁盘传输到网络套接字,减少了 CPU 的负担和数据传输时间,提高了服务器的并发处理能力 。

(3)第三种实现方式:splice

splice是 Linux 系统提供的另一个用于实现零拷贝的数据传输系统调用,它主要用于在两个文件描述符之间直接传输数据,避免数据拷贝 。 splice的原理是通过使用管道(pipe)作为中介,实现数据在两个文件描述符之间的高效传输 。在splice操作中,至少有一个文件描述符必须是管道文件描述符 。当调用splice时,内核将数据从源文件描述符读取到管道的内核缓冲区,然后再将数据从管道的内核缓冲区传输到目标文件描述符 。在这个过程中,数据始终在内核空间中流动,没有经过用户空间,从而避免了数据拷贝 。

splice适用于多种场景,特别是在需要对数据进行处理但又要避免数据拷贝的情况下 。在代理服务器中,需要将接收到的网络数据转发到另一个网络连接,使用splice可以直接在内核空间完成数据的转发,而不需要将数据拷贝到用户空间进行处理,提高了数据转发的效率 。此外,在一些需要高效处理大量数据的场景,如大数据处理、日志收集等,splice也能发挥重要作用,减少数据处理的开销,提高系统性能 。

3.3零拷贝优势分析

零拷贝技术作为一种高效的数据传输优化方式,在性能提升、降低延迟以及资源节约等方面展现出显著优势 。

从性能提升角度来看,零拷贝技术最直接的影响就是减少了 CPU 和内存带宽的占用 。在传统的数据传输方式中,数据需要在用户空间和内核空间之间多次拷贝,每一次拷贝都需要 CPU 参与,消耗 CPU 资源 。而零拷贝技术通过避免数据在用户空间的拷贝,减少了 CPU 用于数据拷贝的时间,使得 CPU 可以将更多的时间和资源用于其他更有价值的任务,如业务逻辑处理等 。

以文件传输为例,传统方式下,数据从磁盘读取到内核缓冲区后,还需要拷贝到用户空间缓冲区,再从用户空间缓冲区拷贝到内核空间的套接字缓冲区,这个过程中 CPU 需要进行多次数据搬运操作 。而采用零拷贝技术,如sendfile,数据可以直接在内核空间从磁盘传输到网络套接字,大大减少了 CPU 的工作量,提高了数据传输的吞吐量 。同时,由于减少了数据在内存中的多次移动,内存带宽的占用也相应降低,使得系统能够更高效地利用内存资源,提升整体性能 。

在低延迟方面,零拷贝技术也有着出色的表现 。减少上下文切换是实现低延迟的关键因素之一 。在传统的 I/O 操作中,每次系统调用都伴随着用户态和内核态的上下文切换,这种切换需要保存和恢复寄存器状态、更新内存管理信息等,会消耗一定的时间 。零拷贝技术通过减少系统调用次数以及避免数据在用户空间和内核空间之间的频繁切换,降低了上下文切换的开销,从而有效减少了数据传输的延迟 。在实时通信、流媒体传输等对延迟要求极高的场景中,零拷贝技术能够确保数据快速地从源头传输到目的地,为用户提供更流畅、实时的体验 。

资源节约是零拷贝技术的又一重要优势 。由于减少了 CPU 和内存带宽的占用,系统可以将这些资源分配给其他需要的进程或任务,提高了系统资源的利用率 。这在多任务并发执行的环境中尤为重要,能够使得系统更加稳定、高效地运行 。此外,零拷贝技术还可以减少内存的使用 。在传统的数据传输中,为了存储多次拷贝的数据,需要额外分配大量的内存空间 。而零拷贝技术避免了数据的重复拷贝,减少了内存的需求,特别是在处理大量数据时,能够显著降低内存的压力,提高系统的整体稳定性和可靠性 。

四、共享内存与零拷贝结合应用

4.1实际场景案例

(1)数据库系统:在数据库系统中,共享内存和零拷贝技术的结合发挥着至关重要的作用,显著提升了数据库的读写性能。以 MySQL 数据库为例,在数据读取过程中,当客户端请求数据时,数据库内核首先会检查共享内存区域中是否有所需的数据。如果数据存在,就可以直接从共享内存中获取,避免了从磁盘再次读取数据的开销,这利用了共享内存多个进程可直接访问同一块内存区域的特性 。若共享内存中没有所需数据,数据库会通过零拷贝技术将数据从磁盘直接读取到共享内存,具体实现方式可能是通过mmap将磁盘文件映射到共享内存区域,减少数据在用户空间和内核空间之间的拷贝次数。这样,不仅减少了数据读取的时间,还降低了 CPU 和内存带宽的占用 。

在数据写入时,多个数据库进程可能会同时对共享内存中的数据进行修改。例如,在一个高并发的电商数据库中,多个订单处理进程可能同时更新订单状态数据。共享内存的高效通信能力使得这些进程可以直接在共享内存中操作数据,而零拷贝技术则确保了数据在写入磁盘时的高效性,减少了数据在内存中的多次拷贝,提高了数据库的并发写入性能 。

(2)分布式缓存系统:分布式缓存系统如 Redis,通过共享内存和零拷贝技术的协同工作,实现了快速的数据存储和读取。在 Redis 集群中,多个节点之间需要共享缓存数据,共享内存提供了一种高效的共享方式。当一个节点需要读取缓存数据时,它可以直接从共享内存中获取,无需通过网络进行数据传输,大大提高了读取速度 。

在数据更新方面,当一个节点对缓存数据进行更新时,通过共享内存,其他节点可以立即感知到数据的变化。零拷贝技术则在数据从内存写入磁盘持久化的过程中发挥作用,以sendfile为例,它可以将内存中的数据直接传输到磁盘,避免了数据在用户空间和内核空间之间的多次拷贝,提高了数据持久化的效率,确保了缓存数据的一致性和可靠性 。

(3)视频流处理系统:在视频流处理系统中,共享内存和零拷贝技术的结合可以实现高效的视频数据处理和传输。以在线视频平台为例,视频数据从存储设备读取后,通过零拷贝技术(如sendfile)直接传输到共享内存区域。多个视频处理进程,如视频解码、转码等进程,可以直接从共享内存中读取视频数据进行处理 。

在视频数据传输到客户端的过程中,同样利用共享内存和零拷贝技术。服务器将处理后的视频数据存储在共享内存中,通过零拷贝技术将数据直接发送到网络套接字,减少了数据在内存中的多次拷贝,提高了视频流传输的效率,确保了视频播放的流畅性,为用户提供更好的观看体验 。

4.2代码示例与实践

下面我们给出一个使用共享内存和零拷贝技术实现进程间高效通信的完整代码示例,以 C 语言为例,详细解释代码逻辑和关键步骤。

#include <sys/ipc.h>#include <sys/shm.h>#include <sys/mman.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <semaphore.h>#define SHM_SIZE 1024#define FILE_NAME "test.txt"intmain(){    int shm_fd, file_fd;    void *shared_mem, *file_mem;    sem_t *semaphore;    struct stat file_stat;    // 创建共享内存对象    shm_fd = shm_open("/shared_memory", O_CREAT | O_RDWR, 0666);    if (shm_fd == -1) {        perror("shm_open failed");        exit(EXIT_FAILURE);    }    // 配置共享内存大小    if (ftruncate(shm_fd, SHM_SIZE) == -1) {        perror("ftruncate failed");        close(shm_fd);        exit(EXIT_FAILURE);    }    // 将共享内存映射到进程地址空间    shared_mem = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);    if (shared_mem == MAP_FAILED) {        perror("mmap shared memory failed");        close(shm_fd);        exit(EXIT_FAILURE);    }    // 打开文件    file_fd = open(FILE_NAME, O_RDONLY);    if (file_fd == -1) {        perror("open file failed");        munmap(shared_mem, SHM_SIZE);        close(shm_fd);        exit(EXIT_FAILURE);    }    // 获取文件状态    if (fstat(file_fd, &file_stat) == -1) {        perror("fstat failed");        close(file_fd);        munmap(shared_mem, SHM_SIZE);        close(shm_fd);        exit(EXIT_FAILURE);    }    // 使用mmap将文件映射到内存    file_mem = mmap(0, file_stat.st_size, PROT_READ, MAP_PRIVATE, file_fd, 0);    if (file_mem == MAP_FAILED) {        perror("mmap file failed");        close(file_fd);        munmap(shared_mem, SHM_SIZE);        close(shm_fd);        exit(EXIT_FAILURE);    }    // 创建信号量用于同步    semaphore = sem_open("/semaphore", O_CREAT, 06660);    if (semaphore == SEM_FAILED) {        perror("sem_open failed");        munmap(file_mem, file_stat.st_size);        close(file_fd);        munmap(shared_mem, SHM_SIZE);        close(shm_fd);        exit(EXIT_FAILURE);    }    // 模拟数据传输,将文件数据拷贝到共享内存    strncpy(shared_mem, file_mem, SHM_SIZE);    // 发送信号通知其他进程数据已准备好    if (sem_post(semaphore) == -1) {        perror("sem_post failed");    }    // 等待其他进程处理数据    if (sem_wait(semaphore) == -1) {        perror("sem_wait failed");    }    // 清理资源    if (sem_close(semaphore) == -1) {        perror("sem_close failed");    }    if (sem_unlink("/semaphore") == -1) {        perror("sem_unlink failed");    }    munmap(file_mem, file_stat.st_size);    close(file_fd);    munmap(shared_mem, SHM_SIZE);    close(shm_fd);    if (shm_unlink("/shared_memory") == -1) {        perror("shm_unlink failed");    }    return 0;}
  1. 创建共享内存:使用shm_open函数创建一个共享内存对象,指定名称为/shared_memory,权限为可读可写。如果创建失败,打印错误信息并退出程序 。
  2. 配置共享内存大小:通过ftruncate函数将共享内存的大小设置为SHM_SIZE,这里设置为 1024 字节 。
  3. 映射共享内存:使用mmap函数将共享内存映射到当前进程的地址空间,使得进程可以直接访问共享内存 。
  4. 打开文件并映射文件到内存:打开指定的文件test.txt,获取文件状态,然后使用mmap将文件映射到内存,实现零拷贝读取文件数据 。
  5. 创建信号量:为了实现进程间的同步,创建一个信号量/semaphore,初始值为 0 。信号量用于控制数据的读写顺序,确保发送方和接收方能够协调工作 。
  6. 数据传输:将映射到内存的文件数据拷贝到共享内存中,模拟数据从文件传输到共享内存的过程 。
  7. 同步操作:发送信号通知其他进程数据已准备好,然后等待其他进程处理完数据后发送的信号 。
  8. 清理资源:在程序结束时,关闭和删除信号量,解除文件和共享内存的映射,关闭文件和共享内存对象,并删除共享内存 。

通过这个代码示例,可以看到共享内存和零拷贝技术如何在实际应用中协同工作,实现进程间的高效数据传输和共享 。在实际应用中,可以根据具体需求对代码进行扩展和优化,例如增加错误处理、提高代码的健壮性等 。

五、注意事项与常见问题

5.1同步与互斥问题

在共享内存的使用中,多进程并发访问共享内存时,极易出现竞态条件,导致数据不一致等问题 。例如,在一个多进程协作的文件服务器系统中,多个进程可能同时对共享内存中的文件缓存数据进行读写操作 。如果没有有效的同步机制,当进程 A 正在读取共享内存中的文件数据时,进程 B 可能同时对该数据进行修改,这就会导致进程 A 读取到不完整或错误的数据 。

为了解决这些问题,通常需要使用信号量、互斥锁等同步机制 。信号量是一种整型变量,它通过一个计数器来控制对共享资源的访问 。在共享内存场景中,当一个进程想要访问共享内存时,它首先需要获取信号量(通过sem_wait操作),如果信号量的值大于 0,说明有可用资源,进程可以访问共享内存,同时信号量的值减 1;如果信号量的值为 0,进程将被阻塞,直到信号量的值大于 0 。当进程访问完共享内存后,需要释放信号量(通过sem_post操作),使信号量的值加 1 。通过这种方式,信号量可以确保同一时间只有一个或指定数量的进程能够访问共享内存 。

互斥锁则是一种更简单直接的同步机制,它就像一把锁,一次只能被一个进程持有 。当一个进程想要访问共享内存时,它必须先获取互斥锁(通过pthread_mutex_lock操作),如果互斥锁未被其他进程持有,该进程可以获取锁并访问共享内存;如果互斥锁已被其他进程持有,该进程将被阻塞,直到持有锁的进程释放锁(通过pthread_mutex_unlock操作) 。在一个多进程的数据库缓存系统中,多个进程可能会同时尝试更新缓存数据,使用互斥锁可以确保同一时间只有一个进程能够对缓存数据进行修改,避免数据冲突 。

5.2内存管理与资源释放

及时解除共享内存映射和删除共享内存是避免内存泄漏和资源浪费的关键 。当进程不再需要使用共享内存时,如果不及时调用 shmdt 解除共享内存与进程虚拟地址空间的映射,即使进程结束,该共享内存仍会被占用,导致内存资源无法被其他进程使用,造成内存泄漏 。在一个长时间运行的服务器程序中,如果存在多个进程频繁地创建和使用共享内存,但没有及时解除映射,随着时间的推移,系统的内存资源会逐渐被耗尽,影响系统的正常运行 。

同样,当所有进程都不再使用共享内存时,及时调用shmctl删除共享内存也是非常重要的 。如果不删除共享内存,它将一直存在于系统中,占用内核资源 。特别是在共享内存使用频繁的场景下,如大型数据库系统或分布式计算平台,不及时删除共享内存会导致内核资源被大量占用,降低系统的性能和稳定性 。为了确保资源的有效利用,在程序设计中,应养成良好的习惯,在进程结束前或不再需要共享内存时,及时调用 shmdt 和 shmctl 进行资源的释放和清理 。

5.3权限控制

设置共享内存访问权限对于确保数据安全和合法访问至关重要 。在创建共享内存时,可以通过shmget函数的shmflg参数来设置访问权限,这些权限类似于文件的访问权限,包括读权限(SHM_R)、写权限(SHM_W)等 。在一个多用户的服务器环境中,不同用户的进程可能会访问共享内存 。如果不设置合理的权限,可能会导致数据泄露或被非法修改 。例如,将共享内存设置为所有用户可读可写权限(0666),可能会使未授权用户的进程访问和修改共享内存中的敏感数据,如数据库的用户认证信息等 。

为了保障数据安全,应根据实际需求精确设置权限 。只允许特定用户组的进程对共享内存进行读写操作,可以将权限设置为用户组可读可写,其他用户无权限(0660) 。在设置权限时,还需要考虑进程的运行环境和用户身份,确保权限设置符合安全策略 。同时,在程序运行过程中,应避免动态修改共享内存的权限,防止权限被恶意篡改,确保数据的安全性和完整性 。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-28 12:38:22 HTTP/2.0 GET : https://f.mffb.com.cn/a/476229.html
  2. 运行时间 : 0.104765s [ 吞吐率:9.55req/s ] 内存消耗:4,899.80kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2ea611ccd19fff7b874a2ed713467987
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000507s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000814s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000327s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000266s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000548s ]
  6. SELECT * FROM `set` [ RunTime:0.000218s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000489s ]
  8. SELECT * FROM `article` WHERE `id` = 476229 LIMIT 1 [ RunTime:0.002631s ]
  9. UPDATE `article` SET `lasttime` = 1772253502 WHERE `id` = 476229 [ RunTime:0.007589s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000254s ]
  11. SELECT * FROM `article` WHERE `id` < 476229 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000498s ]
  12. SELECT * FROM `article` WHERE `id` > 476229 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000428s ]
  13. SELECT * FROM `article` WHERE `id` < 476229 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.008273s ]
  14. SELECT * FROM `article` WHERE `id` < 476229 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.005070s ]
  15. SELECT * FROM `article` WHERE `id` < 476229 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.013457s ]
0.106373s