kmalloc 相关资料总结

内核中与驱动相关的内存操作之五(kmalloc) 在内核空间里面获取一段内存区域,最常用到的API就是kmalloc. 1.原型(lk2.6.22)如下: static inline void *kmalloc(size_t size, gfp_t flags)     2.参数说明: size:     要分配内存空间的大小,以字节为单位. flags:     分配标志,用来控制kmalloc的行为.主要如下: 阅读详情

LINUX KERNEL “kmalloc”

1.     函数原型

void * kmalloc (size_t size, int flags);

存在于<linux/slab.h>中。

2.     函数简要说明

Kmalloc提供了再设备驱动程序或者内核中动态分配内存的方式,kmalloc函数返回的是虚拟地址(线性地址),分配的内存在物理上是连续的,这对于要进行DMA的设备十分                                           真实的物理地址只有一个固定的偏移,因此存在比较简单的转换关系。Kmalloc最多只能分配32*PAGE_SIZE大小的内存,一般PAGE_SIZE=4KB,也就是128KB大小的内存,这128KB的内存还要有16个字节用来页面描述结构。

3.     参数说明

2.1参数含义

size: 需要分配的内存字节数

flags: 分配内存的类型

2.2参数描述

size_t 类型定义在cstddef头文件中,该文件是C标准库的头文件stddef.h的C++版。它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。

size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int。size_t的设计就是为了适应多个平台的,增加程序在不同平台上的可移植性。

 

kmalloc的flags参数决定了要分配的内存的类型,kmalloc提供了多种内存分配行为,使用flags标志,可以控制kmalloc的行为。

所有的flags都定义在 <linux/gfp.h>中。

下表给出针对不同的flags的不同含义:

flags

含义(说明,使用情况)

GFP_KERNEL

1.       最常用的flag,代表一个在内核空间运行的线程进行调用,只能在进程内核空间调用,就是说函数是代表一个进程在执行一个系统调用,如果内存不足则当前进行会进行睡眠。

2.       只能在用户进程上下文中使用,是最可靠的内存分配方式。

3.       并不是总是正确的内存分配方式,如果在进程上下文之外调用kmalloc则会出错。

4.       允许在分配内存时如果内存不足进行睡眠进行等待,因此这时分配函数必须是可以重入的。

5.       如果在处理进程上线文之外的请求,例如中断处理、tasklet以及内核时钟等,则不允许睡眠等待内存,应使用GFP_ATOMIC。

GFP_ATOMIC

1.       用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.

2.       能够实现分配即使是最后一个空闲页,如果最后的页都不是空闲页,则分配失败。

3.       没有GFP_KERNEL分配内存可靠,应该有良好的内存溢出处理策略。

GFP_USER

1.       用来为用户空间页来分配内存。

2.       可能睡眠。

GFP_HIGHUSER

1.       和GFP_USER,如果存在高端内存则进行分配高端内存。

GFP_NOIO

1.       这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求

2.        GFP_NOIO 根本不允许任何 I/O 初始化。

GFP_NOFS

1.       这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求

2.       一个 GFP_NOFS 分配不允许进行任何文件系统调用

GFP_DMA

1.       分配给ISA DMA少于16M的内存。

2.       非常的不可靠,尽量不要用。

 

上面列出的flags能够与下面给出的flags通过“或”操作进行扩充:

flags

含义(说明,使用情况)

__GFP_DMA

这个标志要求分配在能够 DMA 的内存区,是平台依赖的。

__GFP_HIGHMEM

这个标志指示分配的内存可以位于高端内存.

__GFP_COLD

正常地, 内存分配器尽力返回"缓冲热"的页 -- 可能在处理器缓冲中找到的页. 相反, 这个标志请求一个"冷"页, 它在一段时间没被使用. 它对分配页作 DMA 读是有用的, 此时在处理器缓冲中出现是无用的. 

__GFP_NOWARN

这个很少用到的标志阻止内核来发出警告(使用 printk ), 当一个分配无法满足.

__GFP_HIGH

这个标志标识了一个高优先级请求, 它被允许来消耗甚至被内核保留给紧急状况的最后的内存页.

__GFP_REPEAT

__GFP_NOFAIL

__GFP_NORETRY

 

这些标志修改分配器如何动作, 当它有困难满足一个分配. __GFP_REPEAT 意思是" 更尽力些尝试" 通过重复尝试 -- 但是分配可能仍然失败. __GFP_NOFAIL 标志告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的; 可能从不会有有效的理由在一个设备驱动中使用它. 最后, __GFP_NORETRY 告知分配器立即放弃如果得不到请求的内存.

 

4.     内存分配说明

Linux 内核把内存分为 3 个区段: 可用于DMA的内存(位于一个特别的地址范围的内存, 外设能够在这里进行 DMA 存取)、常规内存和高端内存(为了访问(相对)大量的内存而存在的一种机制)。目的是使每种电脑平台都必须知道如何将自己特定的内存范围归类到这三个区段中,而不是任何RAM都相同。所以就出现了上面flags中的__GFP_HIGH分配高端内存的这种flag。

但是,虽然在使用kmalloc的时候可以指定需要分配的内存的大小,但是实际使用的时候,内核只能分配一些预定义的、指定大小的字节数组。kmalloc 能够处理的最小内存块是 32 或 64 字节(体系结构依赖),而内存块大小的上限随着体系和内核配置而变化。考虑到移植性,不应分配大于 128 KB的内存。

5.     区别:kmalloc, vmalloc,malloc

1.      Kmalloc与vmalloc是在系统的内核内存中进行内存分配,而malloc是在用户内存中进行分配;

2.      Kmalloc保证分配的内存在物理上是连续的,vmalloc保证分配的内存在虚拟地址空间是连续的,但是物理地址是否连续不保证;

3.      Kmalloc分配的内存大小有限,最大为128K,而vmalloc和malloc能分配的内存相对较大;

4.      内存在被DMA访问的时候需要使用kmalloc分配物理上连续的内存。

 

6.     Kmalloc重要性

在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,vfree,或free_pages。 kmalloc函数返回的是虚拟地址(线性地址)。 kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要。 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA。

内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间。在驱动程序中不能直接访问,要通过kernel函数vremap获得重新映射以后的地址。

很多硬件设备需要比较大的一块连续的内存用作DMA传送,这块内存需要一直驻留内存,不能被交换到文件中去,所以这个时候需要使用kmalloc在物理内存映射区域进行内存分配,这个时候分配的内存的地址在3G~3G+160M之间。

7.     基本原理描述

7.1分配内存

对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,Linux提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。

进程的4GB内存空间被人为的分为两个部分:用户空间与内核空间。用户空间地址分布从0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB为内核空间。

内核空间中,从3G到vmalloc_start这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页框表mem_map等等),比如我们使用的 VMware虚拟系统内存是160M,那么3G~3G+160M这片内存就应该映射物理内存。在物理内存映射区之后,就是vmalloc区域。对于 160M的系统而言,vmalloc_start位置应在3G+160M附近(在物理内存映射区与vmalloc_start期间还存在一个8M的gap 来防止跃界),vmalloc_end的位置接近4G(最后位置系统会保留一片128k大小的区域用于专用页面映射)

kmalloc和get_free_page申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系,virt_to_phys()可以实现内核虚拟地址转化为物理地址:

#define __pa(x)((unsigned long)(x)-PAGE_OFFSET)

extern inlineunsigned long virt_to_phys(volatile void * address)

{

return__pa(address);

}

上面转换过程是将虚拟地址减去3G(PAGE_OFFSET=0XC000000)。

与之对应的函数为phys_to_virt(),将物理地址转化为内核虚拟地址:

#define __va(x)((void *)((unsigned long)(x)+PAGE_OFFSET))

extern inline void* phys_to_virt(unsigned long address)

{

return__va(address);

}

 

7.2   LINUX内核物理内存分配函数分析

kmalloc() 函数本身是基于 slab 实现的。slab 是为分配小内存提供的一种高效机制。但 slab 这种分配机制又不是独立的,它本身也是在页分配器的基础上来划分更细粒度的内存供调用者使用。也就是说系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc() 再在这上面根据调用者的需要进行切分。

先来看一下 virt_to_phys() 与phys_to_virt 这两个函数。顾名思义,即是虚拟地址到物理地址和物理地址到虚拟地址的转换。函数实现十分简单,前者调用了__pa( address ) 转换虚拟地址到物理地址,后者调用 __va(addrress ) 将物理地址转换为虚拟地址。再看下__pa __va 这两个宏到底做了什么。

#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)

#define __va(x) ((void *)((unsignedlong)(x)+PAGE_OFFSET))

通过上面可以看到仅仅是把地址加上或减去PAGE_OFFSET,而PAGE_OFFSET 在 x86 下定义为 0xC0000000。这里又引出了疑问,在 linux 下写过 driver 的人都知道,在使用 kmalloc() 与__get_free_page() 分配完物理地址后,如果想得到正确的物理地址需要使用 virt_to_phys() 进行转换。那么为什么要有这一步呢?我们不分配的不就是物理地址么?怎么分配完成还需要转换?如果返回的是虚拟地址,那么根据如上对 virt_to_phys() 的分析,为什么仅仅对 PAGE_OFFSET 操作就能实现地址转换呢?虚拟地址与物理地址之间的转换不需要查页表么?代着以上诸多疑问来看 VMM相关的引导代码。

直接从start_kernel() 内核引导部分来查找 VMM相关内容。可以看到第一个应该关注的函数是 setup_arch(),在这个函数当中使用paging_init() 函数来初始化和映射硬件页表(在初始化前已有 8M内存被映射,在这里不做记录),而 paging_init() 则是调用的pagetable_init() 来完成内核物理地址的映射以及相关内存的初始化。在pagetable_init() 函数中,首先是一些 PAE/PSE/PGE 相关判断与设置,然后使用 kernel_physical_mapping_init() 函数来实现内核物理内存的映射。在这个函数中可以很清楚的看到,pgd_idx是以PAGE_OFFSET为启始地址进行映射的,也就是说循环初始化所有物理地址是以 PAGE_OFFSET 为起点的。继续观察我们可以看到在 PMD 被初始化后,所有地址计算均是以 PAGE_OFFSET 作为标记来递增的。分析到这里已经很明显的可以看出,物理地址被映射到以 PAGE_OFFSET 开始的虚拟地址空间。这样以上所有疑问就都有了答案。kmalloc() 与__get_free_page() 所分配的物理页面被映射到了 PAGE_OFFSET 开始的虚拟地址,也就是说实际物理地址与虚拟地址有一组一一对应的关系。

综上所述,循环初始化所有物理地址都是以PAGE_OFFSET为起点的,物理地址被映射到以PAGE_OFFSET开始的虚拟地址空间,所以kmalloc所分配的物理页面被映射到以PAGE_OFFSET开始的虚拟地址,这样就和物理地址存在一个直接的一一对应的关系,所以通过kmalloc分配得到的虚拟地址减去PAGE_OFFSET就可以获得证实的物理地址,而不用查找页表进行转换。

8.     kmalloc总结

1.      用于在设备驱动程序或者内核模块中动态的分配内存;

2.      最大只能分配128K内存,其中还有16字节用来记录页描述结构;

3.      Kmalloc参数中flags参数决定了如何进行内存分配,不同的分配方式决定不同的实现方式;

4.      在kmalloc参数中指定分配的内存的大小,但是实际分配的内存可能比指定的大,因为kmalloc只能分配一些预定义的、指定大小的字节数组,能分配的最小的内存块是32或者64字节(操作系统依赖);

5.      Kmalloc分配的内存物理地址连续的,特别适合用作DMA传送的硬件设备;

6.      Kmalloc分配内存以后返回的虚拟地址,是物理地址加上一个PAGE_OFFSET的地址,获取物理地址只需要减去PAGE_OFFSET,而不用去查找页表;

7.      Kmalloc分配的内存驻留内存,不会被交换到文件中;

8.      Kmalloc分配的内存在内核空间中,存在与物理内存映射区域(3G~vmalloc_start);

9.      Kmalloc用于小内存分配;

详解kmalloc、vmalloc IA-32环境下的Linux对用户进程分配4G的虚拟地址空间,低3G是用户独立的空间,高1G是内核空间。用户空间的动态内存分配用malloc,而在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc。释放内存用的是kfree,vfree,或free_pages. kmalloc函数返回的是虚拟地址(线性地址). kmalloc – 内核分配内存void * 阅读详情

相关推荐

Kmalloc详解

用于在kernel中为object申请小于一页的内存。object就是经常会用到的一些结构体,如task_struct。提前将内存分割成不同大小的块,用于一些常用的内存请求,尽可能避免了外部内存碎片,要知道从伙伴系统申请内存至少都要一页,就是4kb,这对于一些可能只需要几字节的需求来说太大了!具体可以去看下slab和伙伴系统的原理,这里不做详述。kmalloc是一个总的kernel内存申请的调用接口,根据申请内存的大小来判断是从伙伴系统申请还是从slab分配器申请。大于2。

2503_90541313的博客 2339

kernel阅读手记之kmalloc

<br />内核中,分别对于不同的应用层面,对kmalloc有不同的定义,分别位于<br />slab.c<br />Mark Hemment捣鼓的,从从Sun OS引进<br />slob.c<br />针对嵌入式系统,主要是针对内存非常有限的设备<br />slub.c<br />可以说是对slab的重新设计,代码量更下,并且能够更好的适应large NUMA系统,被认为时slab和slob的取代者<br /> <br /> <br />Slob中的kmalloc只有一个语句,return __kmal

lcw_202的专栏 1837

[linux kernel]slub内存管理分析(3) kmalloc

linux内核内存管理算法slub源码分析之kmalloc 内存分配逻辑

Breeze的博客 6182

linux 内核内存分配

linux 内核内存分配

wince_lover的专栏 4448

Linux内存管理(38):slub 分配器之kmalloc详解

在之前的 slub 系列博文中,详细地分析了slub 分配的初始化、创建、对象分配、对象释放的原理, linux 系统为内核一些连续内存申请提供了 kmalloc 接口,为此专门创建了不同大小的kmalloc caches,详细可以查看《slub 分配器初始化》第5节。本文在此基础上详细分析 kmalloc 相关接口。

私房菜 1360

避坑指南:WSL2网络模式修改导致无法上网的解决方案(附备份还原技巧)

本文深入解析WSL2默认网络隔离机制,并提供三种安全的端口互通方案,重点推荐通过配置Windows防火墙规则实现稳定访问。同时,针对网络配置修改可能引发的无法上网问题,给出了从重置配置到系统级备份的完整恢复指南,确保开发环境安全可靠。

jj890的博客 780

为什么linux内核函数出现错误,返回值是一个负数

该疑问出现与我看《linux内核设计与实现》这本书的12.3.2这节中下面一段代码:page = __get_free_pages(GFP_KERNEL,3); if (!page){ /*没有足够的内存:你必须处理这种错误!*/ return -ENOMEM; }1.如何理解函数返回指针内核中的函数通常以返回指针的形式来传递调用函数后执行的结果,返回值指针有

开坦克的飞行员 2973

433MHz无线通信避坑指南:如何解决信号干扰和误码问题

本文深入探讨433MHz无线通信中的信号干扰和误码问题,提供从射频前端设计到协议优化的全链路解决方案。通过天线匹配、电源噪声抑制、曼彻斯特编码改进及实时频点切换等技术,显著提升通信稳定性和距离。适合智能家居和工业无线控制系统的开发者参考。

weixin_29288313的博客 415

Kmalloc和Vmalloc的区别

kmalloc对应于kfree,可以分配连续的物理内存; vmalloc对应于vfree,分配连续的虚拟内存,但是物理上不一定连续。

Emily_rong_2021的博客 879

基于PID的定速巡航控制系统设计【MATLAB源码+Word文档】

本文详细介绍了定速巡航控制是一种车辆驾驶辅助系统,它能让驾驶者在高速或长途驾驶时,设定一个固定的车速,然后车辆会自动维持这个速度行驶,无需驾驶者持续踩油门。这大大减轻了驾驶者的疲劳,同时也提高了行驶的安全性。PID定速巡航控制系统是一种利用比例(Proportional)、积分(Integral)和微分(Derivative)控制算法来实现车辆定速巡航的先进系统。这种系统能够根据设定的速度,自动调整油门开度或制动力度,使车辆保持恒定的速度行驶。这种控制系统具有响应速度快、控制精度高、稳定性好等优点。

weixin_761237174的博客 1667

ubuntu恢复分区表——testdisk

testdisk恢复ubuntu分区表testdisk介绍安装testdisk使用testdisk恢复分区表 testdisk介绍 testdisk 具有广泛的功能,包括恢复丢失或损坏的分区和使不能启动磁盘可以重新启动,也经常被用来恢复被误删的文件。 安装testdisk 如果系统分区表被删除,需要使用ubuntu的启动盘,选择try ubnutu模式进入试用系统。 1、可以直接在终端安装testdisk: sudo apt-get install testdisk 通过命令直接打开testdisk: t

ZNestor的博客 6458

【Linux内核】kmalloc分配内存大小(非常详细)

基于linux-5.15分析。

1万+

C#串口通信从入门到精通(7)——整数/浮点数与二进制、八进制、十六进制之间的转换与C#实现

本文详细介绍由博主开发的DataConvert串口通信帮助类的用法,该帮助类涵盖了串口通信领域所有的数据转换方法,帮助大家快速编写串口通信程序!

qq_34059233的博客 2877

linux内存管理——kmalloc和vmalloc

直接映射区:线性空间中从3G开始最大896M的区间,为直接内存映射区,该区域的线性地址和物理地址存在线性转换关系:线性地址=3G+物理地址。 动态内存映射区:该区域由内核函数vmalloc来分配,特点是:线性空间连续,但是对应的物理空间不一定连续。vmalloc分配的线性地址所对应的物理页可能处于低端内存,也可能处于高端内存。 永久内存映射区:该区域可访问高端内存。访问方法是使用all

phymat.nico的专栏 450

51单片机最强模块化封装(3)

本篇文章将带大家继续封装我们的代码。这里我们会封装数码管的操作函数。我们又封装了一个模块啦,不知道现在大家有没有感受到模块化的强大呢。B站。

m0_49476241的博客 4059

【数据集】30 m地表温度LST数据集

【数据集】30 m地表温度LST数据集

WW、forever的博客 1126

深入浅出内存管理--kmalloc支持的最大内存分配

首先我们来看下kmalloc的实现,本文基于kernel 4.0版本: static __always_inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { -----------(1) if (size &gt; KMALLOC_MAX_CACHE_SIZE)...

程序猿Ricky的日常干货 9141

matlab 质心重合法实现点云配准【2026最新版】

质心重合法是将源点云和目标点云的质心重合,以此缩小两点云集之间的平移误差,从而为下一步粗配准提供更好的初始位置姿态。

点云侠的博客 509

Kmalloc可以申请的最大内存

Kmalloc申请的最大内存 以前虽然读过源码,但是对于它的申请上限确实没注意过。下面分析下,下面是kmalloc的源码。 可以看出,如果想知道kmalloc能申请的范围,需要跳转到<linux/kmalloc_sizes.h>文件中观察。下图便是包含的<linux/kmalloc_sizes.h>文件可以看出,kmalloc一般情况下的上限是128K,但是如果打开了K...

weixin_30612769的博客 949

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

kmalloc使用相关

Kmalloc内存分配和malloc相似,除非被阻塞否则他执行的速度非常快,而且不对获得空间清零。 Flags参数 #include Void *kmalloc(size_t size, int flags); 第一个参数size是要分配的块的大小,第二个参数是分配标志(flags),他提供了多种kmalloc的行为。 最常用的GFP_KERNEL,他表示内存分配(最

bytxl的专栏 2095

计算机控制技术及应用

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

linux kmalloc 函数

异同点kmalloc分配的物理内存是连续的,vmalloc分配的物理内存可以不连续,但是虚拟地址空间连续。kmalloc既支持大块内存分配也支持小块内存分配,大块内存使用页面分配器,小内存使用slab分配器,而vmalloc用于大块内存分配器,并且最好分配内存大小是整页级的,否则会导致内存空间浪费。测试结果如下图所示,插入内核模块分配一块4M(阶数为10)大小的物理内存块,对应的阶数为10,阶数为10的内存块从548减少为547,删除内核模块回收内存块,阶数为10的内存块数量增加一,变为548。...

yongjong的专栏 3452

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

linux kmalloc原理,kmalloc 函数内幕

kmalloc 是个功能强大且高速(除非被阻塞)的工具,所分配到的内存在物理内存中连续且保持原有的数据(不清零)。原型:#include linux/slab.h>void *kmalloc(size_t size, int flags);size 参数内核管理系统的物理内存,物理内存只能按页面进行分配。kmalloc 和典型的用户空间 malloc在实际上有很大的差别,内核使用特别的基于页...

weixin_32531655的博客 909

Linux 内核级通用内存池 —— kmalloc 体系

当申请内存块的尺寸超过 192 字节时,内核会通过 fls 函数来计算 kmalloc_info 数组中的通用 slab cache 索引。

myIddddd的博客 742

49 kmalloc 的实现

这里说的是 内核中分配小对象的一种内存分配方式 kmalloc呵呵 经典程度不必多说了, 内核使用的大多数 不经常使用的小对象基本上是基于 kmalloc这里 我们来看一下 kmalloc, kmalloc 基于 slab, 因此 这里不会赘述太多。

970655147的专栏 449
上一篇: C# 非递归遍历所有子目录与子文件
下一篇: C# XML文件操作总结 SAX DOM 解析
watkins
博客等级 码龄18年 1277粉丝 246原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值