进程地址空间和虚拟内存

别再死记公式了!用Python+LTspice仿真,5分钟搞懂RC低通滤波器截止频率 本文通过Python和LTspice仿真工具,详细介绍了RC低通滤波器的工作原理和截止频率的计算方法。从环境搭建到电路仿真,再到数据分析和可视化,帮助读者直观理解滤波器特性,避免死记硬背公式。文章还提供了参数敏感性实验和实际应用技巧,适合电子工程学习者和爱好者。 阅读详情


前言

以下内容基于80x86的linux虚拟机


一、虚拟内存优点

虚拟内存作为一种逻辑层,处于应用程序的内存请求与硬件内存管理单元(MMU)之间,虚拟内存的优点有:

  • 应用程序所需内存大于可用物理内存时也可以运行

      当物理内存不足是,虚拟内存也可以映射磁盘空间,但是对程序来说还以为自己在使用内存。
    
  • 程序只有部分代码装入内存时进程也可以执行

      当物理内存不足时可以将部分需要执行的代码放入物理内存,暂时不需要执行的代码放入磁盘。
    
  • 程序员可以编写与机器无关的代码,不用关心物理内存的组织结构

      当程序需要申请一块连续内存空间时,其对于的物理内存可能并非连续的,而程序直接操作虚拟内存,则可以当成连续内存来使用。
    
  • 为物理内存提供了保护机制,防止内核地址被用户进程访问,用户进程访问其他用户进程。

      在进程创建时内核会为进程维护一个页表,里面的每一行称为一个页表项,每个页表项包括虚拟内存对应的物理内存地址已经各种标志位,其中User/Supervisor标志位用来描述访问该物理内存需要的特权等级,如果值为1说明是用户进程地址空间任何时候该页框都可以访问,如果值为0说明是内核地址空间,只有切换为内核态时才能访问该内存;内核为进程维护页表时只会利用未被使用的物理内存,虚拟内存的低地址值表示页内偏移offset,所以进程通过虚拟内存访问内存不会影响其他进程。
    

二、基础名词

  • 线性地址:线性地址也称为虚拟地址,是一个32位无符号整数,可以用来表达高达4GB的地址,也就是高达4 294 967 296个内存单元。线性地址通常用16进制数字表示,值的范围从0x00000000到0xffffffff。
  • 物理地址:用于内存芯片级内存单元寻址。他们与从CPU的地址引脚发送到内存总线的电信号像对应。物理地址有32位或36位无符号整数表示。
  • 页:在虚拟内存技术中将虚拟地址空间被划分为固定大小的结构,这个结构称为页,一页通常4KB或8KB。
  • 页框:在虚拟内存技术中将物理内存也划分为固定大小的结构,这个结果称为页框,页框的大小和页保持一致。
  • 字节是存储的最小单元,页是IO的最小单元。

三、虚拟内存实现流程

在80x86的linux虚拟机中由于CPU的最大寻址范围是4GB所以进程的最大虚拟内存空间是4GB一般而言1-3GB为用户空间,3-4GB为内核空间,对于所以进程来说都是如此,所有进程的内核空间的虚拟地址和物理地址都是相同的,而用户空间的虚拟地址相同物理地址不同。原因是内核维持着一组自己使用的页表,这个组页表在系统初始化的时候被创建但不会被任何进程或内核进程使用,而是作为一个模板供进程页表创建时参考,换句话说进程页表的内核地址(虚拟地址范围0xc0000000-0xffffffff)相关的页表项是相同的。

  1. 当进程A被创建时内核参照内核空间页表以及进程A所占用的物理内存空间创建多级页表(全局页目录及各级页表)保存在内存中。
  2. 当进程A分配到CPU资源时内核将进程A的顶级页表地址放入寄存器cr3中,刷新MMU中的TLB缓存。
  3. 当CPU访问进程A中的虚拟地址x时,CPU将内存转换请求传达给MMU,MMU首先看下TLB中有没有,如果有则将虚拟地址x对于物理地址y返回,并通过总线将y的读取指令传达给物理内存RAM,然后物理内存将地址y对于的数据通过总线传给CPU。
  4. 如果TLB中没有则MMU会根据寄存器cr3的值从内存中获取进程A的多级页表(内存中获取相对于TLB来说比较耗时),然后将虚拟地址x转换成2进制拆分成多段分别对于多级页表和页内偏移量,在页表中进行比对,找到对应的页表项。
  5. 查看页表项中的Present标志如果为1说明当前页在内存中,如果为0说明在磁盘中。同时比对User/Supervisor、Read/Write等标志判断是否有权限访问该页(虚拟地址)。
  6. 如果在内存中则将虚拟地址x对于物理地址y返回,同时将虚拟地址x与对于物理地址y的对应关系在TLB中做一份缓存,并通过总线将y的读取指令传达给物理内存RAM,然后物理内存将地址y对于的数据通过总线传给CPU。
  7. 如果当前页在磁盘中则此时会触发一个缺页异常/缺页中断,中断程序通过CPU给对于磁盘管理器发送读取指令进行IO读取,将读取到内存后的物理内存地址更新到页表中并重新执行虚拟地址x的获取指令即重复过程3。

四、多级页表和页表项的标志位

1、页表及页表项的标志位

1.1、一级页表

下图为虚拟内存基于一级页表查找物理内存地址的过程。MMU会将一个32位的虚拟地址分成两部分,由于一页4KB=4096个字节,而字节作为最小的储存单元,所以32位虚拟地址需要划分出12位用于页内字节寻址,剩下的20位高位地址用于和页表比对获取页框起始地址(物理地址),所以虚拟地址P+d基于页表转换成物理地址为R+d。如果前20位在页表中找不到对应页框说明为非法地址访问会抛出异常/触发中断,由对应中断程序处理,这就是虚拟内存机制对物理内存保护的体现防止一个进程的地址空间被其他进程破坏。

上图表格为页表,每一行为一个页表项

1.2、页表项中的标志位

在这里插入图片描述
页表项一般为4字节32位包括:

  • Present标志(上图0位):1代表页框对于的物理地址在内存中;0代表不在内存中,MMU在读取页表项是如果发现present为0则会触发缺页中断。
  • Field标志(上图12-31位):存储页框对于的起始物理地址,由于每一个页框有4KB的容量,所以虚拟地址的后12位记录的是页框内的偏移,所以这里Field只需要记录虚拟地址的高20位对应的物理地址即可。
  • Accessed标志(上图5位):每当CPU对一个页框进行读操作时标记该值,这个值不是由MMU设置,而是由操作系统(CPU)设置。
  • Dirty标志:每当CPU对一个页框进行写操作时标记该值,这个值不是由MMU设置,而是由操作系统(CPU)设置。
  • Read/Write标志(上图1号位):记录该页框是否可读可写。
  • User/Supervisor标志(上图2号位):如果值为1说明是用户进程地址空间任何时候该页框都可以访问,如果值为0说明是内核地址空间,只有切换为内核态时才能访问该内存。
  • PCD/PWT标志(上图3.4号位):记录是否写入高速缓存TLB
  • PageSize标志(上图7号位):如果设置为1,则该页框代表2MB或4MB的大页框
  • Global标志: 用来防止常用页从TLB高速缓存中刷新出去,只有在cr4寄存器的页全局启用标志置位时这个标志才起作用。

2、为什么要有多级页表

在现代操作系统中页表都是多级存在的,在80x86的linux虚拟机中进程的多级页表分别是:页全局目录(CPU寄存器cr3中的值)——>页上级目录——>页中间目录——>页表——>页(offset)。
首先看下一级页表的弊端,4GB的虚拟地址高20位需要2^20个页表项,每个页表项4个字节共需要4MB内存,即一个拥有4GB虚拟内存的进程光页表就需要占用4MB的物理内存,所以需要采用多级页表来减少页表对内存的占用。
多级页表结构

五、TLB

1、什么是TLB

  • 在80x86Linux虚拟机中MMU还包含一个称为转换后援缓冲器或TLB的高速缓存用于加速虚拟地址的线性转换,当一个虚拟地址第一次使用时,通过慢访问内存中的页表计算出相应的物理地址。同时,物理地址被存放在一个TLB表项中,以便以后对同一虚拟地址的引用可以快速得到转换。
  • 在多处理系统中(每个CPU都对应一个MMU内存管理单元),每个CPU都有自己的TLB,这叫做该CPU的本地TLB。多个CPU之间的TLB中对应项不必同步,这是因为运行在各个CPU上的不同进程可能虚拟地址相同但映射的物理地址不同,因为每个进程都有单独的页表。
  • 当CPU的cr3控制器被修改时(进程切换时会修改),内核使当前CPU中的TLB失效,这是因为新的一组页表被启用而TLB指向的是旧数据。CPU不能自动刷新它们自己TLB,因为决定虚拟地址和物理地址直接何时不再有效的是内核而不是硬件。

2、TLB的刷新机制

2.1、TLB刷新的时机
  • 改变内核维持的页表时,由于内核页表作为所有进程内核虚拟地址的映射页表模板,所有影响所有进程的页表,所以此时全部CPU的TBL失效刷新。
  • 更换一个范围内内核页表时,由于内核页表作为所有进程内核虚拟地址的映射页表模板,所有影响所有进程的页表,所以此时全部CPU的指定虚拟地址范围内的TLB失效刷新。
  • 执行进程切换时(cr3被修改),运行当前进程的CPU中非全局页(全局页是指内核地址空间相关页,非全局指进程私有地址空间相关页)相关的TLB失效刷新。
  • 触发缺页异常时,运行当前进程的CPU中单个页表相关的TLB失效刷新。
2.2、cr3寄存器被改变但不触发TLB失效的特殊情况

在进程切换时一般情况下会将CPU的cr3寄存器的值修改为新进程的页全局目录的地址,且当前CPU的TLB会被刷新。不过内核在下列情况下进行进程切换时会避免修改cr3刷新TLB:

  • 相同进程里的线程切换时不会修改cr3寄存器
  • 当两个使用相同页表集的普通进程直接进行系统切换时,由于页表集相同,所以不会修改cr3
  • 当一个普通进程和一个内核线程间执行进程切换时,内核线程并不拥有自己的页表集,更确切的说内核线程使用刚在CPU上执行过的普通进程的页表集,所以不会修改cr3
2.3、懒惰TLB

惰性TLB的目的就是为了避免多处理器系统上无用的TLB刷新,保证懒惰TLB模式下CPU可以专心执行内核进程,不会接受其他与TLB刷新相关的 * 处理器间中断 * 请求
当内核为某个用户态进程分配页框并把页框的物理地址存入页表项时(缺页中断需要完成的事情),它必须刷新本地CPU相应页的TLB区域,在多处理系统中如果有多个CPU正在使用相同的页表集,那么内核还必须刷新这些CPU上使用相同页表集的TLB区域。惰性是指,当CPU收到刷新TLB的指令时,如果此时CPU整处于内核态运行一个内核线程时,TLB的刷新将推迟到切换成用户态后再执行,因为内核态线程几乎不会访问用户进程地址空间。如果CPU处于用户态将即刻刷新对应页的TLB区域。

例子:进程A,B拥有相同的页表集,CPU1正在执行进程A但是遇到了硬件中断切换到内核态运行一个内核线程(硬件中断程序),此时CPU2正在执行B并触发了缺页中断,为进程B分配了新的页框,CPU2的TLB对应区域刷新。

  • 此时当CPU1收到刷新TLB请求时如果 不考虑惰性刷新时 TLB可能刷新1-2次
1. 立即刷新TLB
2. 硬件中断处理完后还是切换成进程B时TLB不刷新,硬件中断处理完后切换成进程C时TLB刷新
  • 此时当CPU1收到刷新TLB请求时如果 考虑惰性刷新时 TLB可能刷新1次
1.硬件中断处理完后还是切换成进程B时延时刷新TLB,硬件中断处理完后切换成进程C时TLB刷新
80x86(DOS)虚拟机 这是一个80x86模拟软件,运行后为dos系统,可以通过mount命令设置文件夹。<br/>格式:mount c: d:\dos<br/>功能:把d:\dos路径映射为C:盘,之后进入c盘就可以访问d:\dos下的文件了。 立即下载

相关推荐

告别AT串口线!用STM32F407的USB FS口直连EC800M进行物联网通信

本文介绍了一种创新的物联网通信方案,利用STM32F407的USB FS接口直连EC800M模块,替代传统的AT串口线连接。通过详细的硬件对比、STM32CubeMX配置和USB驱动调试步骤,展示了如何实现更高效的AT指令通信,同时降低硬件复杂度和功耗。

weixin_29189987的博客 705

1. CPU查找物理寻址和虚拟寻址、虚拟内存优点、不同位数的操作系统虚拟内存大小关系、Linux虚拟内存用户空间和内核空间

虚拟内存可以把同一块物理内存映射到不同的虚拟地址空间,在不同的进程之间实现内存共享对物理内存进行隔离,这样不同进程的操作互不影响虚拟内存空间的大小远远大于实际的物理内存虚拟内存可以提供更大的地址空间,并且地址空间是连续的,这样编写程序去访问会更加简单。

郝开的博客 1876

避开这5个坑!ADNI数据库下载实操经验分享(含断点续传方案)

本文分享了ADNI数据库下载的5个常见陷阱及解决方案,包括高级搜索策略优化、断点续传技巧和数据完整性验证。特别针对大文件下载中断问题,提供了wget断点续传和分卷下载的实操方法,帮助研究者高效获取神经影像数据,避免重复下载和时间浪费。

git9versioner的博客 373

Linux内核的虚拟内存(MMU、页表结构)

如果不在,则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;在映射工作中,为了记录程序段占用物理内存的情况,操作系统的内存管理模块需要建立一个表格,该表格以虚拟地址为索引,记录了程序段所占用的物理内存的物理地址。

嵌入式Linux内核的博客 1699

6.2 磁悬浮轴承:软件架构与实现

本文系统阐述了磁悬浮轴承控制系统的软件架构与实现方法。采用分层架构设计,包括硬件抽象层、实时控制内核、控制算法层和应用层,确保系统实时性和可靠性。重点分析了电流环、位置环等关键控制任务的调度策略,比较了不同硬件平台(DSP、ARM、FPGA)的软件实现方案。强调模块化设计、配置化管理等工程实践,并详细介绍了从算法仿真到系统联调的完整开发流程。最后指出严格的测试验证是保证系统性能的关键,需通过多阶段测试评估起浮时间、稳态精度等核心指标。

技术工作者 751

WSL2迁移后用户名不见了?一招教你快速恢复Ubuntu22.04默认用户

本文针对WSL2迁移后Ubuntu 22.04默认用户名丢失的常见问题,提供了详细的诊断与修复方案。通过分析迁移底层逻辑,指导用户使用`ubuntu2204.exe config --default-user`命令或配置`/etc/wsl.conf`文件快速恢复用户身份,并涵盖权限修复、冲突解决及自动化迁移脚本等进阶内容,确保子系统迁移后环境完整可用。

web39explorer的博客 555

操作系统知识点

深入了解嗷

qq_44836676的博客 2829

【QNX+Android虚拟化方案】136 - QNX 侧 Coredump 文件解析

【QNX+Android虚拟化方案】136 - QNX 侧 Coredump 文件解析

|~~~热爱生活、努力学习的小伙汁~~~| 1905

深入理解计算机系统-之-内存寻址(五)--页式存储管理

前景回顾前面我们讲解了操作系统段式存储管理的主要内容。 32位,在保护方式下,其能够访问的线性地址空间可达4GB,而且允许几乎不受存储空间限制的虚拟存储器程序。虚拟存储器地址空间能够可达64TB。它还提供了复杂的存储管理和硬件辅助的保护机构和增加了支持多任务操作系统的特别优化的指令。实际上,64TB的虚拟地址空间是有磁盘等外部存储器的支持下实现的。在编写程序是可以放在磁盘存储器上,但在执行时,必须把

OSKernelLAB(gatieme) 1万+

深入剖析 Wenet 下 AISHELL-1 的 run.sh 脚本:从数据准备到模型训练

run.sh脚本用于处理 AISHELL-1 数据集的整个训练和测试流程。我们将逐步分析脚本中的每个部分,包括环境变量、参数设置、各个阶段的执行等。stage: 设置脚本的起始阶段(如数据准备)。stop_stage: 设置脚本的结束阶段。通过对 Wenet 下 AISHELL-1 的run.sh脚本的详细剖析,我们希望你能更好地理解每个步骤的功能及其背后的原理。此脚本不仅为模型训练提供了便利,也为用户自定义和扩展训练流程提供了基础。希望本教程能帮助你顺利完成语音识别项目!

帅小柏的博客 1631

【中项第三版】系统集成项目管理工程师 | 第 1 章 信息化发展

【中项第三版】系统集成项目管理工程师 | 第 1 章 信息化发展

静谧、淡雅 6574

x86下TLB的总结

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33796177的博客 386

Python爬虫实战:爬取500+网易云热门歌单,我摸清了全网最火的音乐规律

曲风:流行是主流,“情绪价值”比单纯曲风更重要;歌名:感性、场景化的歌名,更受用户偏爱。这次实战让我明白,Python不是冰冷的代码,而是能帮我们看清生活中隐藏规律的工具。从每天刷的歌单里,用爬虫和数据分析挖出用户的真实偏好,不仅满足了好奇心,还实实在在练会了技能。新手朋友可以从这个项目入手,既练习了爬虫基础,又学会了数据分析的核心逻辑,还能结合自己的音乐兴趣理解数据的意义。现在打开PyCharm,跟着代码跑一遍,你也能从网易云的热门歌单里,挖出属于自己的“音乐规律”!

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1887

物理内存 虚拟内存 和进程地址空间

1. 物理内存:物理内存指的是插在计算机主板内存槽上的实际物理内存,CPU可以直接进行寻址;物理内存的容量是固定的,但是寻址空间却取决于cpu地址线条数,如32位机,则寻址空间为2^32=4G,即最大支持4G的寻址空间,即使我们插入了32G容量的内存条,我们也只能拥有4G的物理内存; 2. 虚拟内存:进程执行需要将代码和数据放在内存中,但是物理内存是有限的,当进程比较多的时候,容易造成内存耗尽,而...

snowman的博客 608

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Linux进程地址空间和虚拟内存

https://blog.youkuaiyun.com/jnu_simba/article/details/8917076 一、虚拟内存 先来看一张图(来自《Linux内核完全剖析》),如下: 分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~3,0具有最高特权级(内核),3则是最低特权级(用户),每当程序试图访问(权限又分为可读、可写和可执行)一个段时,当前特权级CPL...

Likes的博客 1170

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

linux系统编程之基础必备(五):Linux进程地址空间和虚拟内存

一、虚拟内存 先来看一张图(来自《Linux内核完全剖析》),如下: 分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~3,0具有最高特权级(内核),3则是最低特权级(用户),每当程序试图访问(权限又分为可读、可写和可执行)一个段时,当前特权级CPL就会与段的特权级进行比较,以确定是否有权限访问。每个特权级都有自己的程序栈,当程序从一个特权级切换到另一个特权级上执行时,堆栈段也随之改换到新级别的堆栈中。 段选择符:每个段都有一个段选择符。段描述符指明段的大小、访问权.

158

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【QandA C++】内存泄漏、进程地址空间、堆和栈、内存对齐、大小端和判断、虚拟内存等重点知识汇总

栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。栈空间和堆区的大小是由操作系统和编译器决定的,不同系统和编译器可能会有不同的默认值。,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。,而数据的低位,保存在内存的低地址中;,而数据的高位,保存在内存的低地址中;

qq_68993495的博客 589

Linux虚拟内存和进程虚拟地址空间简述

后台开发经常会问此类问题,虽说难度不大,但是知道和不知道还是有区别的。以下的内容总结自《深入理解Linux内核》第一章,仅仅是简述,没有深入研究,毕竟内存管理这一块内容超级多,感兴趣的同学可以去啃啃这本书。 虚拟内存 所有新近的Unix系统都提供了一种有用的抽象,叫虚拟内存(virtual memory)。虚拟内存作为一种逻辑层,处于应用程序的内存请求与硬件内存管理单元(Memory Manag...

fuyuande的博客 917

UNIX环境高级编程——Linux进程地址空间和虚拟内存

一、虚拟内存分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~3,0具有最高特权级(内核),3则是最低特权级(用户),每当程序试图访问(权限又分为可读、可写和可执行)一个段时,当前特权级CPL就会与段的特权级进行比较,以确定是否有权限访问。每个特权级都有自己的程序栈,当程序从一个特权级切换到另一个特权级上执行时,堆栈段也随之改换到新级别的堆栈中。段选择符:每个段都有...

weixin_34195546的博客 196

linux进程虚拟地址空间,Linux进程地址空间和虚拟内存

二、linux进程地址空间由前面可得知,进程有4G的寻址空间,其中第一部分为“用户空间”,用来映射其整个进程空间(0x0000 0000-0xBFFF FFFF)即3G字节的虚拟地址;第二部分为“系统空间”,用来映射(0xC000 0000-0xFFFF FFFF)1G字节的虚拟地址。如下图将其更加详细地展示如下:环境变量:类似linux下的PATH,HOME等的环境变量,子进程会继承父进程的环境...

weixin_42449583的博客 187

浅析物理内存、虚拟内存和进程的地址空间

   ●在一个系统中,进程是和其他进程共享CPU和主存资源。但是共享资源会造成一些不可避免的问题,例如由于存储器不够而         进程无法运行,亦或是存储器被外来的恶意进程破坏等。 早期的内存管理机制:  分派方式一:程序载入   1》CPU要访问进程中的数据,必须通过访问访问物理内存的方式(物理寻址)         当CPU要执行某条指令时,它会生成一个有效物理地址,通过存...

a_struggling_monkey的博客 5216

Linux系统编程基础知识-Linux进程地址空间和虚拟内存

转载自:Linux进程空间和虚拟内存 一、虚拟内存 先来看一张图(来自《Linux内核完全剖析》),如下: 分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~3,0具有最高特权级(内核),3则是最低特权级(用户),每当程序试图访问(权限又分为可读、可写和可执行)一个段时,当前特权级CPL就会与段的特权级进行比较,以确

Roykuang的专栏 578
上一篇: CompletableFuture:让你的代码免受阻塞之苦
下一篇: JVM的Reference机制
躺平程序猿
博客等级 码龄8年 4870粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值