Linux系统:内核体系结构,进程管理,进程间通信,对称多处理模型,文件系统

目录

1. Linux简介

2. Linux内核体系结构

2.1 内核 (操作系统) 的职能

2.2 内核组织结构和模块

2.3 内核服务

2.4 /proc文件系统的外部性能视图

2.5 内存管理

3. 进程管理

3.1 进程,任务与内核线程

3.2 调度与上下文交换

4. 进程间通信

4.1 信号

4.2 管道

4.3 系统V的IPC机制

5. Linux对称多处理(SMP)模型

5.1 多处理系统类型

5.2 同步与数据串行化

5.3 锁,锁粒度,锁开销

5.4 cache一致性

5.5 处理器亲和度

6. 文件系统

6.1 虚拟文件系统 VFS

6.2 ext2fs

6.3 LVM和RAID

6.4 磁盘卷组

7. Linux2.6内核新特性


【写在前面】

该文是学习笔记,来源于学习教材的总结。在此记录,仅供自学。如侵删。

1. Linux简介

Linux是能够在众多类型的处理器上运行的操作系统。

Linux支持的处理器: Intel IA-32, Intel IA-64, AMD, DEC, PowerPC, Motorola, APARC, IBM S/390等。

2. Linux内核体系结构

2.1 内核 (操作系统) 的职能

内核的两个主要作用:

(1)与系统的硬件设备进行交互并对其加以控制

(2)为应用程序提供运行环境

类UNIX操作系统向应用程序隐藏了所有的低层硬件细节。

应用程序如果希望使用某个硬件资源,必须向操作系统发出请求,操作系统对请求进行评估,并在请求有效时代表应用程序与硬件设备进行交互。

操作系统依赖于硬件设备禁止与应用程序直接交互的能力。

2.2 内核组织结构和模块

Linux是单核结构(monolithic),因此虽然Linux被划分成控制系统各种组件的多个子系统,但所有的子系统都紧密集成在一起,构成整个内核。

微内核(microkernel)操作系统提供了最少量的功能集合,所有其他的操作系统层次都在微内核之上,以进程方式执行。由于各个层次之间存在着消息传递,微内核操作系统的效率较低,但这类操作系统便于扩展。

2.3 内核服务

内核为在用户模式中运行的应用程序提供了一组与系统进行交互的接口。这些接口称为系统调用。

应用程序可以通过接口访问硬件和其他内核资源。

系统调用不仅为应用程序提供了抽象化的硬件层次,还确保了系统的安全和稳定性。

大多数应用程序并不直接使用系统调用。

相反,在编程时采用了应用程序接口(API)。

注意:在API和系统调用之间不存在关联。API是作为库文件的组成部分提供给应用程序使用的,这些API一般通过一个或多个系统调用来实现。

2.4 /proc文件系统的外部性能视图

/proc文件系统为用户提供了关于内核内部数据结构的视图。

可以利用它查看和修改内核的某些内部数据结构,从而改变内核的行为。

/proc文件系统提供了一种通过微调系统资源来改善应用程序以及系统整体性能的简单方法。

/proc文件系统是一种由内核以动态创建方式生成数据的虚拟文件系统。

它被组织成多种目录形式,其中每个目录都对应于特定子系统的可调选项。

2.5 内存管理

Linux的内存管理问题,包括:地址空间,物理内存,内存映射,分页机制,交换机制。

(1)地址空间

虚拟内存的优点之一,是每个进程都认为自己拥有所需的全部地址空间。

虚拟内存的大小可以是系统中物理内存大小的许多倍。

系统中的每个进程都有自己的虚拟空间,这些虚拟空间相互之间完全独立。

运行个某个应用程序的进程不会影响到其他进程,应用程序之间也是相互保护的。

虚拟空间由操作系统映射至物理内存。

从应用程序的角度来说,这个地址空间是一个线性的平面地址空间,但内核对用户虚拟空间的处理有很大的不同。

线性地址空间被划分为两部分:用户地址空间 + 内核地址空间

用户地址空间不会再每次发生上下文切换时都改变,而内核地址空间则始终保持不变。

为用户空间和内核空间分配的空间容量主要取决于系统是32还是64位的体系结构。(具体的划分大小由内核配置变量PAGE_OFFSET决定)

(2)物理内存

Linux使用与体系结构无关的方式来描述物理内存。

物理内存可以组织成内存体(bank)的结构,每个内存体与处理器的距离都是特定的。

越来越多的机器采用非一致性内存访问(Nonuniform Memory Access, NUMA)技术。

Linux VM 以节点来表示这种排列方式。每个节点划分为许多称为管理区的内存块,它们代表了内存中的地址范围。

有三种不同的管理区:

ZONE_DMA:一切ISA设备对于可以在哪些地址上执行I/O操作具有限制条件,该管理区可以消除这些限制。

ZONE_NORMAL:用于所有的内核操作和分配,对于系统性能很重要。

ZONE+HIGHMEM:是系统中其余的内存。注意,该管理区无法用于内核的分配和数据结构,只能用于保存用户数据。

(3)内存映射

举例x86是32位体系结构,它只支持4GB的地址空间,其中3GB为用户空间保留,1GB分配给内核地址空间。内核将ZONE_DMA和ZONE_NORMAL中的物理内存直接映射到其地址空间,意味着系统中最前面的896MB物理内存被映射到内核虚拟空间,从而只剩下128MB的虚拟空间。这128MB的虚拟空间用于注入vmalloc和kmap等操作。

如果物理内存容量较小(少于1GB),这种映射机制运作良好。

目前的所有服务器都支持数十千兆字节的内存。

Intel公司在其Pentium处理器中引入物理地址扩展机制,能够支持最多64GB物理内存。

前面的内存映射机制使得如何处理高达数十千兆字节的物理内存,成为x86 Linux的一个主要问题来源。

Linux内核按照如下方式处理高端内存(896MB以上的所有内存)。

当Linux内核需要寻址高端内存中的某个页面时,通过kmap操作将该页面映射到一个小的虚拟空间窗口中,在该页面上执行操作,解除对该页面的映射。

注:64位体系结构的地址空间很大,不存在这类问题。

(4)分页机制

虚存有多种实现方式,最有效的是基于硬件的方案。

虚拟空间被划分成固定大小的内存块,称之为页面。

虚存访问通过页表被转换成物理内存地址。

为了支持各种体系结构和页面尺寸,Linux采用了三级分页机制。

提供了三种页表类型:

1)页面全局目录:Page Global Directory, PGD

2)页面中层目录:Page Middle Directory, PMD

3)页表:Page Table, PTE

地址转换提供了一种将进程的虚拟空间与物理地址空间分离的方法。

每个虚存页面都可以在主内存中标记为“存在”或“不存在”。

如果进程访问某个不存在的虚存地址,硬件就会产生一个页面错误,并由内核对其进行处理。

内核处理该错误时将该页面至于主内存中。

在这个过程中,系统可能需要将现有的某个页面替换掉,以便为新页面提供空间。

替换策略是分页系统最关键的内容之一。

(5)交换机制

交换是当主存容量不足时,将整个进程移入或移出辅助存储器的过程。

由于上下文切换的开销很大,许多操作系统,包括Linux,都不采用这种方法,而是采用分页机制。

Linux中,交换是在页面层次而不是在进程层次上执行的。

交换的优点:扩展了进程可用的地址空间。当内核需要释放内存以便为新页面提供空间时,可能需要丢弃一些较少使用或未使用的页面。某些页面因为未被磁盘备份而不容易释放,需要被复制到后背存储器(交换区)中,在必要时,还要从后备存储器中读回。

交换机制的主要缺点是的速度慢。磁盘的读写速度通常都非常慢,因此应该尽量消除交换操作。

3. 进程管理

3.1 进程,任务与内核线程

(1)任务只是一种需要完成的工作的一般性描述,可以是一个轻权的线程,也可以是一个完整的进程。

(2)线程时最轻权的任务实例。在内核中创建线程的成本可能很高,也可能很低,取决于线程需要拥有的特征。最简单的情形是线程与其父线程共享所有资源,包括代码,数据和许多内部数据结构,而仅在区分该线程与其他线程上有一点点差异。

(3)进程是一个重权的数据结构。如果有必要,多个线程可以在单个进程中运行并共享该进程的一些资源。Linux中,进程只是一个拥有全部重权特征的线程。

线程和进程由调度器以相同的方式进行调度。

内核线程是始终在内核模式中运行且没有用户上下文的线程。

内核线程通常针对某个特定功能而存在,很容易在内核中处理它。

内核线程经常具有所期望的作用,能够像其他任何进程一样进行调度,当其他线程需要该功能发挥作用时,为这些进程提供实现该功能的目标线程(通过发送信号)。

3.2 调度与上下文交换

(1)进程调度:确保每个进程能公平分享CPU的一门科学。

Linux当前的调度器程序遵循的原则:一个在所有时候大部分正确的调度器要比一个在大多数时候完全正确的调度更为重要,即缓慢运行的进程要由于因过于精心选择调度策略或错误而停止运行的进程。

(2)上下文切换:当一个进程停止运行,被另一个进程替换时,称为上下文切换。

这个操作的开销很大,内核程序员和应用程序员总是试图尽量减少系统执行上下文切换的数量。

进程可以因为等待某个事件或资源而主动停止运行,或因为系统决定应将CPU分配给另一个进程而被动地放弃运行。对于前者,如果没有其他进程等待执行,CPU实际上可能进入空闲状态。对于后者,该进程或被另一个等待进程所替换,或者分配到一个新的运行时间片或时间周期继续执行。

(3)中断

即使在某个进程正按照有序的方式调度和执行时,也可以被其他更高优先级的任务中断。

信号,中断和异常是不同的异步事件,但在许多方面却类似,并且即使CPU已处于忙状态,他们也都必须被迅速处理。

中断处理程序通常是非常快速和简洁的,因为能够快速处理和清除以便后续数据能够进入。但有时一个中断可能需要处理IDE工作比在中断处理程序中所期望的短时间内完成的工作更多。

中断也需要一个定义良好的环境来完成其工作(注意:中断利用了某个随机进程的资源)。

这种情况下,要收集足够信息,将工作延迟提交至bottom half处理程序进程处理。bottom half处理程序会不时的被调度执行,当前的Linux版本中不鼓励使用这种机制。

4. 进程间通信

4.1 信号

信号用于将事件通知给一个或多个进程,是用户进程间一种原始的通信和同步方式,信号也可以用于作业控制。

内核能够产生一组已定义的信号,系统中的其他进程如果拥有适当的权限,也可以产生信号。

进程可以忽略所生成的大多数信号,但有两个例外:SIGSTOP 和 SIGKILL。

SIGSTOP信号导致进程终止执行,而SIGKILL信号导致进程退出并被忽略掉。

除了SIGSTOP 和 SIGKILL信号外,进程可以决定如何处理其他各种信号。比如进程可以阻塞信号,也可以自己处理信号或允许内核处理信号。

如果由内核处理信号的话,那么内核执行该信号的默认动作。

Linux保存了关于每个进程如何处理各种可能信号的信息。

信号并不是在生成之后就会立即传递给进程,而是当该进程恢复运行时才被传递。每当进程退出一个系统调用时,如果存在着任何未被阻塞的信号,这些信号都会被传递。

Linux与POSIX标准兼容,因此进程可以指定当调用特定的信号处理例程时需要阻塞哪些信号。

4.2 管道

(1)什么是管道

管道是未结构化的先进先出单向数据流。写入者向管道的一端添加数据,读取者从管道的另一端获取数据,而已读取的数据会从管道中删除。管道提供了简单的流控制机制。

(2)实例: $ ls | less

将ls命令的输出结果(目录中的文件)通过管道连至less命令(标记文件的页码)的标准输入中。

Linux还支持命名管道(named pipe)。命名管道跟管道不同,它不是临时对象,而是文件系统中可以通过mkfifo命令创建的实体。

4.3 系统V的IPC机制

Linux支持3种进程间通信机制,最初出现在UNIX系统V中。

这3种机制是消息队列,信号量,共享内存。

这些机制都共享通用的认证方法。

进程只需通过系统调用将唯一的访问标识符传递给内核,就可以访问这些资源。

对这些系统V IPC对象的访问要通过访问许可检查,类似检查文件访问的方式。

系统 V IPC 对象的访问权限由该队形的创建者通过系统调用进行设置。

(1)消息队列

消息队列允许一个或多个进程向其中写入消息,然后这些消息将由一个或多个读出进程读取。

消息队列在功能上等同于管道,但与管道相比,消息队列更为通用,并由多方面的优势。

消息队列通过消息而不是未格式化的字节流形式来传递参数,从而更易于处理数据。

消息可以与类型相关联,因此接受者可以在处理非紧急消息之前检查紧急消息。

当多个进程共享同一个消息队列时,类型域也可用于指定具体接收者。

(2)信号量

信号量是支持原子操作set和test的一些对象,用于实现各种同步协议。

信号量适于被描述成控制多个进程访问共享资源的计数器。

信号量经常作为一种锁定机制,当一个进程对特定资源执行操作时,放置另一个进程访问该资源。

(3)共享内存

共享内存允许一个或多个进程通过这些进程的虚拟空间中的公共内存进行通信。

对共享内存区域的访问要通过密钥和访问权限检查加以控制。

当内存被共享时,并不会检查进程使用该内存的方式。

每个希望共享该内存的进程必须通过系统调用挂接到该虚存上。

进程可以自己选择共享内存在其虚拟空间中的位置,或者让Linux选择一块足够大的空闲区域。

进程第一次访问共享虚存中的某个页面时,会发生页面错误。

Linux改正这个页面错误时,会分配一个物理页面并为之创建一个页表项。

之后,其他进程对该页面的访问会将页面添加到虚拟空间中。

当进程不再希望共享某块虚存时,可以卸离这些虚存,如果还有其他进程仍在使用这块内存,那么卸离操作仅会影响当前进程。当共享该内存的最后一个进程与之相卸离时,会释放这块共享内存的当前物理内存页面。

如果共享虚存没有被锁定到物理内存中,会导致进一步的复杂性。

这种情况下,可以在高端内存使用期间将共享内存的页面替换到系统的交换磁盘上。

5. Linux对称多处理(SMP)模型

5.1 多处理系统类型

多处理系统由大量通过总线或网络进行通信的处理器组成。

多处理系统分为:

(1)松耦合系统

松耦合系统由独立工作的处理器组成。每个处理器都拥有自己的总线,内存和I/O子系统,并通过网络截止和其他处理器通信。可以是同构,也可以是异构。

(2)紧耦合系统

紧耦合系统由多个共享内存,总线和设备的处理器组成。

这类系统只运行单个操作系统实例。可以分为对称系统和非对称系统。在非对称系统的配置中,每个处理器都会分配到一个特定任务。非对称系统通过一个“主”处理器来控制其他所有处理器。而对称系统以相同方式对待所有处理器:进程可以平等地访问所有的系统资源。在对称系统模型中,所有任务被均匀地分散到全部处理器中。

对称系统又划分为专用cache系统和共享cache系统。对称多处理器SMP系统成为许多大型服务器的默认选择。

5.2 同步与数据串行化

由N个处理器构成的SMP系统的执行效率,是单处理器系统的N倍。但在现实中,不存在具有百分之百扩充能力的SMP系统,其主要原因是维护额外的处理器需要一定的开销。

5.3 锁,锁粒度,锁开销

(1)锁机制:实质上是为了防止多个线程同时访问或修改一段关键信息。

这种机制主要应用于通过多个处理器同时执行多个线程的SMP系统上。

(2)锁机制的问题在于如果两个或多个处理器同时竞争同一把锁的话,只有一个处理器可以获得该锁,另一个处理器只能等待该锁被释放。

即,其他处理器实际并未执行任何有用的工作,锁定状态必须限制在尽量短的时间内。

(3)解决这个问题的另一种通用技术,是采用更细粒度的锁机制。在更细粒度的锁机制中,通常并不会通过单把锁来保护100个资源,而是使用100把锁对其加以保护。实际这个方案比较难实现。

(4)锁机制的开销也需要考虑。所有的锁技术都是有代价的。操作系统的设计人员需要选择正确类型的锁定原语,以解决权限问题。Linux2.6中删除了大多数全局锁,多数锁定原语都被优化至极低的开销。

5.4 cache一致性

cache一致性问题发生在多处理器环境中。由于每个处理器都有自己的cache,因此系统中存在着特定数据的多个副本。当修改这些数据时,只有一个处理器的cache拥有该数据的新值,而其他处理器中的cache仍保留旧值。

5.5 处理器亲和度

是改进系统性能的最重要因素之一。

当进程党文系统中的各种资源时,关于这些资源的大量信息将存储于处理器的cache中,因此基于cache友好性warmth的原因。

一个进程保持在同一个处理器上执行时更好的方案。在某些体系结构尤其是NUMA中,某些资源与同一个系统中的其他资源相比距离处理器更近。

这些系统中,处理器亲和度对于系统性能来说很重要。

6. 文件系统

文件系统是操作系统最重要的部件之一。

6.1 虚拟文件系统 VFS

Linux支持多种文件系统。使得Linux可以和其他操作系统共存。

虚拟文件系统(Virtual File System, VFS)允许Linux支持许多中常常会有很大差别的文件系统。

每种文件系统都向虚拟文件系统提供一个公共的软件接口。

Linux文件系统的所有细节都由软件解释,以便所有的文件系统对于Linux内核的其他部分以及系统中运行的程序来说看上去都是相同的。

通过Linux虚拟文件系统层可以透明地同时挂接许多不同类型的文件系统。

Linux虚拟文件系统额的实现方式要能够尽量快速高效地访问文件,它也必须保证可以正确地维护文件和其中的数据。

6.2 ext2fs

Linux上世纪的第一个文件系统是ext2fs。这个文件系统是使用最广泛最流行的。

该文件系统具有高度的稳健性,并支持典型文件系统所提供的各种通常特性。比如:对文件系统对象如文件,目录,硬链接,软链接,设备相关文件,套接字和管道等进行创建,修改和删除的能力。

但系统崩溃会导致ext2文件系统处于不一致的状态。

整个文件系统在重新挂接之前需要进行验证并校正不一致性。

这种长时间的延迟在生产环境中是无法忍受的,该问题通过日志(journaling)的支持可以解决。

ext2的新变型ext3文件系统支持日志机制,这种机制的基本思想是在执行每个文件系统操作之前都记录其日志。

因此,如果机器在两个操作的间隙发生崩溃,只需查看日志记录就可以将文件系统恢复到一致的状态。

6.3 LVM和RAID

(1)磁盘卷管理器为计算机物理存储设备提供了具有多种作用的逻辑抽象。在磁盘数量众多的系统中,卷管理器可以将多个磁盘组合成单个逻辑单元,从而增加了存储空间总量以及数据冗余支持。在但磁盘系统红,卷管理器可以将磁盘空间划分成多个逻辑单元,每个单元用于不同的目的。通常,卷管理器可以对文件系统和更高层的应用程序隐藏物理存储的特征。

(2)链家磁盘冗余阵列 RAID是一种磁盘卷管理器机制。该机制可以将多个物理磁盘组合起来,以便提供I/O吞吐率或改进数据冗余。RAID包括多个级别,每个级别都提供了物理磁盘以及一组不同性能和冗余特征的组合。

(3)Linux提供了4个RAID级别

1)线性RAID:

将多个磁盘简单地传戒起来组成磁盘卷。这种卷类型的容量是所有磁盘容量的总和。该RAID级别没有提供数据冗余支持。如果卷中的某个磁盘发生故障,则在该磁盘上存储的数据将丢失。

2)RAID-0:

是简单的分条(stripping)技术。分条意味着想磁盘卷中写数据时,将数据交叉保存到该卷所有磁盘上相同大小的存储块中。即,卷的第一个存储块写入到第一个磁盘中,以此类推。但卷重的最后一个磁盘被写入后,将返回第一个磁盘,并继续按这种模式进行。该RAID级别改进了I/O吞吐率。

3)RAID-1:

是镜像(mirroring)技术。在镜像词牌卷重,所有数据都被复制到卷中的全部磁盘之上,意味着由N个磁盘创建的RAID-1磁盘卷能够承受(n-1)个磁盘发生故障的情形。另外,由于卷中所有磁盘都包含相同的数据,卷的读操作可以分不到各个磁盘中,从而提高了读操作吞吐率。另一方面,卷的单个写操作会导致对每个磁盘都生成一个写操作,从而降低了写操作吞吐率。RAID-1的另一个负面影响是成本问题,拥有n个磁盘的RAID-1盘卷的成本是单个磁盘的n倍。却只提供了单个磁盘的存储容量。

4)RAID-5:

是带有奇偶检验的分条技术。该类技术类似RAID-0,但每个磁盘中有一个存储块包含的是奇偶校验信息而不是数据。利用这些奇偶检验信息,RAID-5盘卷能够承受卷重任何单个磁盘的故障。类似于RAID-0,RAID-5通过将大型的I/O请求划分到多个磁盘,也提高了读操作吞吐率。但写操作吞吐率会降低,因为每个写请求也需要更新响应磁盘的奇偶校验信息。

6.4 磁盘卷组

(1)磁盘卷组(volume-group, VG)

在各种磁盘卷管理器中,都使用了磁盘卷组的概念。

磁盘卷组是多个磁盘的集合,这些磁盘也称为物理卷(Physical Volume)。物理卷所提供的存储空间可用于创建逻辑卷(Logical-volume, LV)。

磁盘卷组的主要优点是能够在逻辑卷和物理卷之间加以抽象。VG从PV中获取存储空间,并将其划分成固定大小的磁盘块,称为物理区块(Physica-Extent, PE)。通过将一个或多个PE分配给LV,就可以创建LV。这个分配过程可按照任意顺序完成,并不依赖于各个PV的排序或各个PE在特定PV上的顺序。这样易于调整LV的大小。如果需要扩充某个LV,磁盘卷组中任何未用的PE都可以被分配到该LV的尾端。如果需要缩小某个LV,则只需要释放出被分配到该LV尾端的PE。

磁盘卷组本身的大小也易于调整。可以将新的物理卷添加到磁盘卷组中,这时该物理卷上的存储空间变为未分配的新物理区块。这些新的PE就可以用于扩充现有的LV活创建新的LV了。另外,如果一个PV的任何PE都没有分配给任何LV,那么可以从磁盘卷组中删除该PV。

除了扩充和缩小LV之外,LV上的数据可以在磁盘卷组内移动。这种移动可通过将LV中的一个区块重新分配给VG中其他某处的另一个未用PE来完成。当执行这种重分配操作时,旧PE中的数据被复制到新PE中,然后旧PE被释放。

磁盘卷组中的PV不必是单个磁盘,也可以是RAID盘卷。这样用户可以同时获得这两种磁盘卷管理机制的好处。

(2)设备相关文件

Linux系统至少拥有一个硬盘,一个键盘和一个控制台。这些设备由其相应的设备驱动程序控制。

用户级应用程序该如何访问硬件设备?

设备相关文件是操作系统为应用程序提供的设备访问接口,也称为设备结点,保存在/dev目录中。文件中包含了主-辅编号对,用于标识所支持的具体设备。这类文件与普通文件类似,也有文件名,所有权和访问权限等属性。

有两类设备相关文件:块设备和字符设备。

块设备:可以对保存在设备中的数据进行数据块层次上的访问。

字符设备:允许对设备进行字符层次上的访问。

在某个设备上执行ls -l命令时,返回的许可权字符串如果以a,b起始,则表示这是一个块设备。如果以a,c起始,则表示是一个字符设备。

(3)devfs

虚拟文件系统devfs对所有设备的名称进行管理。

devfs是驻留在root文件系统之上的特殊块设备结点和字符设备结点的一种替代系统。

edvfs减少了为系统中的每个设备创建设备结点这项系统管理任务,可以自动处理该工作。

设备驱动程序可以通过设备名称而不是通过传统的主-辅编号机制想devfs注册设备。其结果是设备名称空间不受主-辅编号数目的限制。

系统管理员可以在不同的挂载点多次挂接devfs文件系统,但对设备结点的改动反映在全部挂节点的所以设备结点上。另外,devfs的名称空间甚至被挂接前就存在于内核中。这使得设备结点的可用性独立于root文件系统的可用性。

传统的解决方案,在/dev目录下问系统中每个潜在的设备都创建一个设备结点,而不考虑设备是否真正存在。而在devfs中,只维护必要且足够的设备项就可以了。

7. Linux2.6内核新特性

(1)支持新型体系机构(x86, 64)

(2)超线程/SMT支持

(3)(0)1复杂度的调度器

(4)抢占式支持

(5)NUMA

(6)NPTL

(7)I/O调度器支持

(8)块层次上的重写

(9)AIO

(10)新型文件系统

(11)ACL

(12)Sysfs

(13)Udev

(14)网络功能的改进

(15)Linux安全模块

(16)处理器亲和度

(17)模块重写

(18)同一驱动程序模型

(19)LVM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值