首页 > 编程知识 正文

php伪协议(查看当前目录下空间的使用情况)

时间:2023-05-05 22:39:39 阅读:83579 作者:4035

linux内核相关视频解析:

90分钟了解Linux内存架构、numa优势、slab实现、vmalloc原理Linux多线程的epoll原理分析和reactor原理及应用

字节可能是Linux中最可寻址的存储器单元,但抽象为内存托管的是页面。 本文首先讨论Linux中的内存管理,然后探索从内核操作用户地址空间的方法。

Linux内存

Linux中,用户内存和内核内存是独立的,安装在不同的地址空间中。 地址空间被虚拟化意味着地址是从物理内存中抽象出来的。 因为地址空间是虚拟的,所以可以存在很多地址空间。 实际上,内核本身位于地址空间中,每个进程都位于其自己的地址空间中。 这些地址空间由虚拟内存地址组成,许多具有独立地址空间的进程可以引用相对较小的物理地址空间(计算机中的物理内存)。 这不仅方便,而且安全。 由于各地址空间是独立孤立的,因此是安全的。

但是,这种安全是有代价的。 每个进程(和内核)可以在同一地址引用不同的物理内存空间,因此不能立即共享内存。 幸运的是,有几种解决方案。 用户进程可以通过便携式UNIX操作系统接口(POSIX )共享内存机制(shmem )。 请注意,每个进程都有不同的虚拟地址,其地址可能指向同一物理内存区域。

从虚拟内存到物理内存的映射是通过底层硬件中安装的页表实现的(参见图1 )。 硬件本身提供映射,但内核管理表及其配置。 如所示,一个进程可能有很大的地址空间,但请注意它是稀疏的。 也就是说,地址空间中的小区域(页面)通过页面表引用物理内存。 这样,进程就可以拥有仅针对特定时间所需的页面定义的大量地址空间。

图1 .页表提供了从虚拟地址到物理地址的映射

具有为进程稀疏性定义内存的能力意味着底层物理内存可能会被过度提交。 寻呼(在Linux上通常称为交换,但它会将非活动页面动态移动到磁盘等低速存储设备,以存储需要访问的其他页面(请参见图2 )。 这种行为使计算机中的物理内存能够为容易需要APP的页面提供服务,并将不需要的页面迁移到磁盘上以提高物理内存的利用率。 请注意,某些页面可以浏览文件。 在这种情况下,如果数据不干净(通过页面缓存),则可以刷新数据。 或者,如果页面很漂亮,可以很容易地丢弃数据。

图2 .交换通过将非活动页迁移到速度慢、成本低的存储区,可以更高效地使用物理内存空间。

无MMU体系结构并不是所有处理器都有MMU。 因此,uClinux分发版(微控制器Linux )支持单一地址空间的操作。 虽然此体系结构缺少MMU保护,但可以在不同类型的处理器上运行Linux。

更换为保存的页面的过程称为页面替换算法,可以使用最近使用的算法数量等多种算法来实现。 当请求页面不在内存中的内存位置,内存管理单元[MMU]中不存在映射时,会发生此操作。 此事件称为页面故障,由硬件(MMU )检测,发生页面故障被中断,然后由固件进行管理。 请看图3,对这个堆栈进行说明。

Linux提供了有趣的交换实现,并提供了一些有用的特性。 在Linux交换机系统中,可以创建和使用多个交换分区和优先级。 这允许使用具有不同性能特性的交换设备层,如固态磁盘上的主交换区域[ssd]和低速存储设备上的较大辅助交换区域。 通过向SSD交换区域添加更高的优先级,可以使用到变空为止。 只有这样,页面才会写入优先级较低(较慢)的交换分区。

图3 .从虚拟地址到物理地址映射的地址空间和元素

不是所有页面都是交换的候选页面。 考虑响应中断的内核代码,或管理页表和交换逻辑的代码。 这些是明显的页面,不应该被交换,因此被钉死或永久存在于记忆中。 虽然内核页面不是交换的候选页面,但是用户空间页面可以使用mlock (或mlockall )函数锁定页面。 这就是用户空间内存访问函数背后的目的。 如果内核假定用户传递的地址是有效且可访问的,最终会发生内核死机。 例如,假设由于用户页面被交换,内核中发生了页面错误。 这个APP编程接口(API )保证了正确处理这些角落的情况。

【文章福利】C/C Linux服务器架构师学习资料加组812855908 (资料来源于C/C,Linux,谷歌技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,Mongoogo

ker,TCP/IP,协程,DPDK,ffmpeg等)

内核API

现在,让我们探索用于操作用户内存的内核API。请注意,这包括内核和用户空间界面,但下一节将探讨其他一些内存API。表1列出了要研究的用户空间内存访问函数。

表1.用户空间内存访问API

正如您所预期的,这些函数的实现可以是依赖于体系结构的。对于x86体系结构,您可以找到在./linux/arch/x86/include/asm/uaccess.h中定义的这些函数和符号,源代码位于./linux/arch/x86/lib/userCopy_32.c和userCop64.c。

数据移动函数的作用如图4所示,因为它与复制所涉及的类型(简单的和聚合的)有关。

图4.使用用户空间内存访问API进行数据移动

Access_ok函数

使用access_ok函数检查要访问的用户空间中指针的有效性。调用方提供指针,指针引用数据块的开始、块的大小和访问类型(无论该区域是要读写的)。功能原型定义为:

access_ok( type, addr, size );

这个type参数可以指定为VERIFY_READ或VERIFY_WRITE。这个VERIFY_WRITE符号还标识内存区域是否可读和可写。如果该区域可能是可访问的,则该函数返回非零(尽管访问仍可能导致-EFAULT)。这个函数只是检查地址是否可能在用户空间中,而不是在内核中。

GET_USER函数

若要从用户空间读取简单变量,请使用get_user功能。此函数用于简单类型,如char和int,但是更大的数据类型(如结构)必须使用copy_from_user取而代之的是功能。原型接受一个变量(用于存储数据)和读取操作的用户空间中的地址:

get_user( x, ptr );

这个get_user函数映射到两个内部函数中的一个。在内部,此函数确定要访问的变量的大小(基于为存储结果提供的变量),并通过以下方式形成内部调用:__get_user_x。此函数在成功时返回零。一般来说,get_user和put_user函数比它们的块副本更快,如果移动了小类型,就应该使用它。

PUT_USER函数

使用put_user函数将一个简单的变量从内核写入用户空间。喜欢get_user,它接受一个变量(包含要写入的值)和一个用户空间地址作为写入目标:

put_user( x, ptr );

喜欢get_user,put_user函数内部映射到put_user_x函数并在成功时返回0或-EFAULT关于错误。

CLEAR用户函数

这个clear_user函数用于使用户空间中的内存块为零。此函数在用户空间中接受一个指针,大小为零,以字节为单位定义:

clear_user( ptr, n );

内部,clear_user函数首先检查用户空间指针是否可写(通过access_ok),然后调用内部函数(以内联程序集编码)来执行清除操作。这个函数被优化为一个非常紧的循环,使用带有重复前缀的字符串指令。如果操作成功,则返回不可清除的字节数或零字节数。

复制到用户函数

这个copy_to_user函数将数据块从内核复制到用户空间。此函数接受指向用户空间缓冲区的指针、指向内核缓冲区的指针以及以字节为单位定义的长度。该函数在成功时返回零,或非零返回,以指示未传输的字节数。

copy_to_user( to, from, n );

在检查写入用户缓冲区的能力之后(通过access_ok),内部功能__copy_to_user调用,然后调用__copy_from_user_inatomic(见./linux/arch/x86/include/asm/uaccess)XX。H,其中_XX视架构而定是32或64)。此函数(在确定是否执行1、2或4字节副本之后)最终调用复制_to_user_ll`,这是完成实际工作的地方。在损坏的硬件中(在i 486之前,WP位不能从监控模式中获得),页表可能在任何时候发生更改,需要将所需的页面固定到内存中,以便在寻址时不能换掉它们。POST i 486,进程只不过是一个优化的副本。

复制_FROM_USER函数

这个copy_from_user函数将数据块从用户空间复制到内核缓冲区。它接受一个目标缓冲区(在内核空间中)、一个源缓冲区(来自用户空间)和一个以字节为单位的长度。同.一样copy_to_user,该函数在成功时返回零,而非零返回指示复制某些字节数失败的非零。

copy_from_user( to, from, n );

该函数首先检查用户空间中从源缓冲区读取数据的能力(access_ok),然后调用__copy_from_user最终__copy_from_user_ll。从这里开始,根据体系结构的不同,调用将用户缓冲区复制到具有零(不可用字节)的内核缓冲区。优化的装配功能包括管理能力。

Strnlen_user函数

这个strnlen_user函数的用法就像strnlen但假设缓冲区在用户空间中可用。这个strnlen_user函数有两个参数:用户空间缓冲区地址和要检查的最大长度。

strnlen_user( src, n );

这个strnlen_user函数首先检查用户缓冲区是否可通过调用access_ok。如果可以访问,则strlen函数,并且max length争论被忽略了。

Strncpy_from_user函数

这个strncpy_from_user函数将字符串从用户空间复制到内核缓冲区,给定用户空间源地址和最大长度。

strncpy_from_user( dest, src, n );

作为来自用户空间的副本,此函数首先检查缓冲区是否可通过access_ok。类似于copy_from_user,该函数被实现为一个优化的程序集函数(在./linux/arch/x86/lib/userCopy_XX._c中)。

其他内存映射方案

上一节探讨了在内核和用户空间之间移动数据的方法(内核启动了操作)。Linux提供了许多其他方法,您可以在内核和用户空间中使用这些方法来进行数据移动。虽然这些方法可能不一定提供用户空间存储器访问函数所描述的相同功能,但它们在地址空间之间映射内存的能力是相似的。

在用户空间中,请注意,由于用户进程出现在单独的地址空间中,因此必须通过某种形式的进程间通信机制在它们之间移动数据。Linux提供了多种方案(例如消息队列),但最值得注意的是POSIX共享内存(shmem)。此机制允许进程创建内存区域,然后与一个或多个进程共享该区域。请注意,每个进程都可以将共享内存区域映射到各自地址空间中的不同地址。因此,需要相对偏移寻址。

这个mmap函数允许用户空间应用程序在虚拟地址空间中创建映射。这种功能在某些类型的设备驱动程序中很常见(为了性能),允许将物理设备内存映射到进程的虚拟地址空间。在司机内部,mmap函数通过remap_pfn_range内核函数,它提供设备内存到用户地址空间的线性映射。

更进一步

本文探讨了Linux中内存管理的主题(以达到分页之后的位置),然后探讨了使用这些概念的用户空间内存访问函数。在用户空间和内核之间移动数据并不像看起来那么简单,但是Linux包含一组简单的API,这些API为您跨平台管理这项任务的复杂性。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。