iOS&OS X强大的内存管理总结

内存管理(OS)详解 操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情总结来说:如果直接把物理地址暴露出来的话会带来严重问题,比如可能对操作系统造成伤害以及给同时运行多个程序造成困难。... 阅读详情

每一个iOS开发者,都需要理解引用计数这种内存管理方式,只有这样,才能处理好内存管理的问题。

1.内存管理/引用计数

1.1引用计数:

当生成对象的时候,对象的引用计数是1,当有一个新的指针指向这个对象的时候,引用计数+1.当这个指针不指向这个对象的时候,引用计数-1,如此,当引用计数为0时,销毁这个对象。引用计数的这种管理方式类似于Linux文件系统的硬链接,在Linux文件系统中,我们用**ln**命令可以创建一个硬链接(相当于retain),当删除一个文件时(相当于release),系统调用会检查文件的link count值,如果大于1,则不会回收文件所占有的磁盘区域,知道最后一次删除前,系统发现link count值为1,才会执行真正的删除操作。

1.2内存管理的思考方式

1. 自己生成的对象,自己所持有。
    以*alloc  *new  *copy  *mutableCopy开头的方法名生成对象只有自己持有,但是对于allocate newer copying mutableCopyed方法则不成立以上规则。
    id obj = [[NSObject alloc] init];
    //这里retainCount为1
    NSLog(@"%ld",[obj retainCount]);
2. 非自己生成的对象,自己也能持有。
    不是自己生成的对象,需要通过retain方法来持有对象。
    id obj = [NSMutableArray array];
    [obj retain];
3. 不在需要自己所持有的对象时释放
    不管是以alloc/new/copy/mutableCopy还是以retain方法持有的对象,当不再需要时,都需要调用release方法来释放。
    [obj release];
4. 非自己持有的对象无法释放
   当自己不持有某个对象时,如果释放的话,就会导致程序崩溃。
    id obj = [NSMutableArray array];
    [obj release];

1.3 苹果的实现方式

对于retainCount/retain/release这三个方法,_CFDoExternRefOperation函数按retainCount/retain/release操作进行分发,调用不同的函数。从调用的函数名可以猜出苹果的实现大概就是采用散列表来管理引用计数的(表键值为内存块地址的散列值)
采用散列值的好处:
1.  引用计数表各记录中存在内存块地址,可从各个记录中追溯到各对象的内存块。
2. 如果出现故障导致对象占用的内存块损坏,但只要引用计数表没坏,就能够确认各内存块的地址。
3. 在利用工具监测内存泄漏时,引用计数表的各个记录有助于监测各对象的持有者是否存在。

1.4 autorelease

NSAutoreleasePool对象的生存周期相当于c语言的自动变量的作用域,对于所有调用过release方法的对象,在废弃NSAutorelease对象时,都将调用release方法。
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];
其实现应该是将对象加到pool的数组变量中,当调用drain时,将数组中全部的对象调用release方法。
如果给NSAutoReleasePool对象调用autorelease方法会怎么样呢?会发生异常。
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool autorelease];


对于NSAutoreleasePool类,autorelease实例方法已经被重载,所以运行时会抛异常。

2.ARC

ARC 能够解决 iOS 开发中 90% 的内存管理问题

2.1 所有权修饰符

在Xcode4.2以后,默认设定对所有的文件ARC有效。
ARC有效时,id类型和对象类型不同于c语言其他类型,类型上必须附加所有权修饰符。
__strong
__weak
__unsafe_unretained
__autoreleasing

1.  __strong 修饰符
id和对象类型在没有明确指定所有权修饰符的时候,默认为__strong修饰符
{
    id __strong obj = [[NSObject alloc] init];
}
附有__strong修饰符的变量obj在超出其变量作用域时,会释放其附有的对象。这点和c语言的自动变量类似。
如果没有__strong的修饰符的MRC是?
{
    id obj = [[NSObject alloc] init];
    [obj release];
}
虽然__strong修饰符能够解决retain,release问题,但是可能会导致循环引用问题。
对象 A 和对象 B,相互引用了对方作为自己的成员变量,只有当自己销毁时,才会将成员变量的引用计数减 1。因为对象 A 的销毁依赖于对象 B 销毁,而对象 B 的销毁与依赖于对象 A 的销毁,这样就造成了我们称之为循环引用的问题,这两个对象即使在外界已经没有任何指针能够访问到它们了,它们也无法被释放。
![图片来自《iOS开发进阶》](https://img-blog.youkuaiyun.com/20160804174033463)
不只是两个对象会出现这种问题,多个对象也会出现循环引用的问题:
![图片来自<<iOS开发进阶>>](https://img-blog.youkuaiyun.com/20160804175252311)

有两种方法可以来解决这个循环引用。

    1.  主动断开循环引用。
    主动断开循环引用多出现于block相关代码逻辑中,比如说网络请求中,网络请求的回调时被持有的,如果回调中存在对ViewController的引用,就会存在循环引用的问题,因为:
    - 1 ViewController持有网络请求对象,
    - 2 网络请求对象持有block回调,
    - 3 如果回调中存在self调用,那么就持有了ViewController,形成了循环引用。

解决办法就是,就是主动断开循环引用,在网络请求结束之后,主动断开对block的持有,将其置空。
不过,主动断开循环引用需要程序员显示的知道哪里需要断开引用,这又和手动来retain和release差不多啦。

还有一种办法就是弱引用,弱引用就是要用到第二个关键字

2. __weak
    弱引用虽然持有对象,但是不增加对象的引用计数,这样就避免了循环引用,但是不能直接给对象符__weak关键字,因为是弱引用,所以一旦创建就会被释放,会有一个错误提示:Assigning retained object to weak variable; object will be released after assignment
NSMutableArray __weak *mutableArrayA = [[NSMutableArray alloc] init];
但是可以这样来消除循环引用:
    id __weak obj = nil;
    NSMutableArray *mutableArrayA = [[NSMutableArray alloc] init];
    obj = mutableArrayA;
    NSMutableArray *mutableArrayB = [[NSMutableArray alloc] init];
    [obj addObject:mutableArrayB];
    [mutableArrayB addObject:obj];
利用xcode的Instruments 工具集可以很快地监测出项目的循环引用,在没有加入__weak关键字之前,在 Xcode 的菜单栏选择:Product -> Profile,然后选择 “Leaks”,再点击右下角的”Profile” 按钮开始检测。

这里写图片描述

这里会有一个图来展示是哪里出现的循环引用,当加入__weak关键字之后就不会出现循环引用问题啦。![这里写图片描述](https://img-blog.youkuaiyun.com/20160807155246596)

最容易出现循环引用的地方就是delegate,两个viewController A和B,A需要弹出B让用户输入一些内容,B将内容返回给A,这时候A的delegate成员变量通常是一个弱引用,避免出现循环引用。
![图片来自《iOS开发进阶》](https://img-blog.youkuaiyun.com/20160807155702652)

系统对于每一个有弱引用的对象,都维护一个表来记录它所有的弱引用的指针地址。这样,当一个对象的引用计数为 0 时,系统就通过这张表,找到所有的弱引用指针,继而把它们都置成 nil。


3. __unsafe__unretained 修饰符

__unsafe__unretained是不安全的修饰符,在ARC中,符有ARC修饰符的变量的内存管理不输入编译器的工作。为什么有这个修饰符,__weak修饰符只能用于iOS5以及OX X Lion以上版本的应用程序,在iOS4及OX X Snow leopard只能用__unsafe__unretained修饰符.

它与__weak修饰符的区别是,用它访问已经释放的对象,但应用程序只会在个别情况下会崩溃,所以在使用__unsafe__unretained的变量,有必要验证该变量是否存在。

4. __autoreleasing

    显示的用__autoreleasing和显示的用__strong一样稀奇,__autoreleasing的作用就是在ARC中加入像非ARC中autorelease的作用。
@autoreleasepool {
        id __autoreleasing obj  = [[NSObject alloc] init];
}
等同于非ARC
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];
id类型的指针或对象指针是默认带有__autoreleasing修饰符的,但是不默认带__strong修饰符。例如:
    NSError *error = nil;
    NSError **pError = &error;
这样赋值会有一个错误:
Pointer to non-const type 'NSError *' with no explicit ownership类型不匹配。
添加上__strong修饰符就没有编译错误。
    NSError *error = nil;
    NSError *__strong *pError = &error;
同理__weak修饰符亦是如此。
在不能使用__strong修饰符和__weak修饰符的c++用智能指针std::shared_ptr和std::weak_ptr对应代替。

2.2 ARC规则

1.  不能使用retain/release/retainCount/autorelease。
2.  不能使用NSAllocateObject/NSDeallocateObject。
3.  须遵守内存管理的方法命名规则。   

在非ARC时,以alloc new copy mutableCopy为名称开始的方法,必须返回给调用方所持有的对象,在ARC中一样适用,但是在ARC中要增加一条规则-init

以init开始的方法必须是实例方法,并且必须返回对象,返回的对象应为id类型或该方法声明类的对象类型,亦或是该类的超类,子类型,该返回对象并不注册到autoreleasepool里面,基本上只是对alloc方法返回值的对象进行初始化。
4.  不要显式调用dealloc。
5.  使用@autoreleasepool块替代NSAutoreleasePool.
6.  不能使用区域(NSZone)
7.  对象型变量不能作为c语言结构体(struct/union)的成员
c语言的结构体成员中,如果存在OC对象型变量,就会报错,因为c语言的规约上没有方法来管理结构体成员的生存周期。要把对象型变量加到结构体成员中,可强制转换为void *或是附加__unsafe_unretained修饰符。
8.  显示转换id和void *
void *转换为id类型,需要__bridge__transfer,意思是被转换的变量所持有的对象在该变量被赋值给转换变量后随之释放。
    void *p = 0;
    id obj = (__bridge_transfer id)p;

在非ARC中,

    void *p = 0;
    id obj = (id)p;
    [obj retain];
    [(id)p release];
id类型转换为void *类型,会用到__bridge_retained,意思是可使要转换赋值的变量也持有所赋值的对象。
    id obj = [[NSObject alloc] init];
    void *p = (__bridge_retained void *)obj;

在非ARC中:

    id obj = [[NSObject alloc] init];
    void *p = obj;
    [(id)p retain];
9.  Core Foundation的内存管理
底层的Core Foundation对象,在创建时大多以XxxCreateWithXxx这样的方式创建,
eg:
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault,”hello,world”,kCFStringEncodingUTF8);

对于这些对象的引用计数的修改,要使用CFRetain 和 CFRelease  除此之外,在ARC下,我们有时需要将一个Core Foundation对象转换成一个Objective-C对象,这个时候告诉编译器,转换过程的引用计数需要做如何的调整,这个过程和void *与id转换类似。

2.3 属性声明的属性对应的所有权修饰符

assign -> __unsafe_unretained修饰符
copy   -> __strong修饰符(但是赋值的是被复制的对象)
retain -> __strong修饰符
strong -> __strong修饰符
__unsafe_unretained —> __unsafe_unretained修饰符
weak   -> __weak修饰符


在 ARC 的帮助下,iOS 开发者的内存管理工作已经被大大减轻,但是我们仍然需要理解引用计数这种内存管理方式的优点和常见问题,特别要注意解决循环引用问题。
AD | Altium Designer(原理图设计、电路仿真、PCB绘图)汉化版 Altium Designer(原理图设计、电路仿真、PCB绘图) 阅读详情

相关推荐

一个三极管和稳压管构成的简易稳压电源

一、对电压精度要求不高的场所可以使用本文中所述的简易稳压电源(电流变化引起 的基极-发射极的压降 变化 对输出电压来说可以容忍)二、根据负载实际需求选择三极管,不同的三极管集电极电流不同,电流放大倍数不同(1、尽量选择负载电流(iC 或 iE)上限时,hFE仍然比较理想的三极管,2、一般三极管对基极电流没有限制,可以适当调整基极电流以获得所需输出电流)

五花带点肉 1万+

NSError笔试题

// 编译错误 NSError *error = nil; // NSError **pError = &error; ////Pointer to non-const type 'NSError *' with no explicit ownership 报错 指向没有明确所有权的非 常量类型“ NSError *”的指针 // 编译正确 NSError *error1 ...

More reading and learning to become excellent 333

Spring Boot 构建war 部署到tomcat下无法在Nacos中注册服务

因此,当使用外部容器时,如此处的 Tomcat 来部署项目,AbstractAutoServiceRegistration 就不能监听到容器启动事件了,也就不会尝试向服务注册中心注册当前这个微服务,那么注册就失败了,并且也就没有异常信息了。自定义获取获取外部容器端口的方法, 然后监听应用启动事件,当应用被启动时,获取外部容器启动的端口号,然后将这个 port 设置到 NacosAutoServiceReigistration 中。在启动类同级目录,复制下面代码即可(不需要修改,直接构建war即可)

ttyy1112的专栏 2519

对象指针

诸如id *obj或者NSError **error这样的对象指针,默认修饰符就是__strong,即id __strong *obj或者NSError * __strong *error,而不是像《Objective-C高级编程:iOS与OS X多线程和内存管理》中说的,默认是__autoreleasing。 给对象指针赋值,所有权修饰符一定要保持一致。 //错误做法 NSError ...

chaoguo1234的专栏 439

2024高教社杯数学建模国赛B题丨国一原创论文解析及源码超详细分享!

继续分享一篇2024国赛B题的国奖论文,包含可运行源代码jupyter,国赛B题通常比较聚焦实际复杂系统的多目标优化决策,主要偏重算法实现与概率建模解决开放性的管理问题。而且高度开放,无标准答案,学科交叉复杂,如资源调度、交通优化、海洋探测等。比较建议有一定统计学基础的同学参加。

ihui永不放弃 6738

GPT-5.5 是真好用!SCI论文润色与学术写作能力上全面提升,全流程指令已整理好!

输出规范:先输出完整的摘要正文,不添加额外说明,以Markdown表格形式提供中文自检说明,表格包含两列,列标题为“检查项”和“说明”,逐项说明是否已覆盖背景、研究问题、方法、结果及贡献,并简要评价摘要结构与表达是否符合要求,除上述内容外不输出其他信息。:你是一位(学术写作专家/期刊审稿人/论文评审专家),精通学术写作规范、逻辑结构、语法准确性及学术表达方式,你的任务是帮助提升论文的质量,包括语言润色、语法检查、逻辑优化和降低重复率。语言需简洁、正式、具有概括性,不展开具体论述,仅提供结构与要点说明。

智能AI让学术科研更容易 289

Pointer to non-const type 'PLTexture*'with no explicit ownership错误,解决办法

在arc项目里引用非arc项目,在引用的.m文件里加了-fno-objc-arc,然后运行会出如下错误:Pointer to non-const type 'PLTexture*'with no explicit ownership,具体如图: 原因是:这里声明的是双指针,加在这里好像识别有问题,然后解决办法就是把上面出错的两句换成下面:  PLTexture *__unsafe_

u010477563的专栏 3290

一个超酷的开源uHand2.0机械手掌项目

uHand2.0是深圳乐幻索尔公司开源的一款机械手掌,它长下面这个样子:1、uHand2.0外观图之前在公众号就分享过视频:学习嵌入式可以带娃,不信你们看2、uHand2.0硬件原理图看...

Bruce.yang的嵌入式之旅 4457

探索 Objective-C 的对象所有权修饰符

引言 大家都知道,Objective-C 有 4 个对象所有权修饰符(Ownership Qualifier),分别是: __strong __weak __unsafe_unretained __autoreleasing 在日常开发中日常用的最多的就是 __weak,几乎都是为了解决循环引用的问题。__strong 是一个变量默认的修饰符,不需要写。__unsafe_unretained 因为它的不安全,基本上不会去使用它。__autoreleasing 见得最多的地方估计就是 NSError * _

刘铎Derek在优快云 408

RK3576 调试ov2735 mipi-csi摄像头

摘要:本文记录了基于RK3576平台调试OV2735 MIPI摄像头的全过程。开发环境采用Linux 6.1内核和Buildroot文件系统。调试步骤包括:1)硬件检查(电源、晶振和引脚连接);2)驱动配置(设备树节点、ISP通道设置);3)驱动验证(通过ID检测和I2C工具测试);4)推流测试(使用v4l2和gstreamer工具)。重点解决了复位引脚配置、时钟命名匹配等关键问题,并通过寄存器检查确保初始化正常。最终实现了摄像头数据流的成功输出,为嵌入式视觉应用开发提供了完整参考方案。

qq_45147279的博客 1060

CenterPoint 工程复现

CenterPoint 工程复现,本文中使用版本:BEVerse工程下的mmdet3d (`MMDet3d v0.17.3`)版本,MMDetection3D中其他版本的使用`大同小异`。

Darchan的博客 5663

【操作系统(OS)】内核原理详细解析,进程管理 内存管理 文件系统管理 设备管理

本文系统介绍了操作系统的核心概念与功能。操作系统作为计算机系统的核心枢纽,负责管理硬件资源并提供统一接口,主要功能包括进程/线程管理、内存管理、文件系统、设备管理和用户接口。文章详细解析了操作系统的分层结构、分类对比以及核心概念,如内核态与用户态的区别,帮助读者全面理解操作系统的基本原理及其在各类计算设备中的应用。掌握这些知识是理解计算机系统运行机制的关键基础。

独立思考,明辨是非 1913

点云配准3:3d-ndt算法在pcl上的实现以及参数设置

3d-ndt算法在pcl上的使用方法以及参数设置

诺有缸的高飞鸟的博客 7891

OS--学习笔记:内存管理

OS--内存管理

weixin_45609535的博客 1611

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

os内存管理

文章目录1.内存管理1.1内存空间的分配与回收:1.2内存空间的扩展1.3地址转换1.4 存储保护: 1.内存管理 1.1内存空间的分配与回收: 待------------ 1.2内存空间的扩展 英雄联盟的大小为12G,那么按照之前的想法,再运行程序前,要将整个程序装入内存,然后我们发现4G的电脑也可以打英雄联盟,这是为什么呢? 定义:把物理小的内存在逻辑上拓展成很大的内存,利用了虚拟技术,操作系统的虚拟性 覆盖技术: 思想:内存中分一个固定区和若干个覆盖区。 1.程序划分为若干个功能上相对独立的

daniu_weilai的博客 806

怀旧版电脑GBC模拟器

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

OS内存管理

记录OS内存管理相关,主要偏向非连续内存管理中虚拟地址和物理之间的映射过程中使用的分页和分段思想

qq_45888932的博客 1069

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

OS---内存空间管理

连续分配方式 为一个用户程序分配一个连续的内存空间 20世纪六、七十年代的OS中,分类: 单一连续分配 固定分区分配 动态分区分配 动态重定位分区分配 其他 (1)单一连续分配 内存分为系统区和用户区两部分: 系统区:仅提供给OS使用,通常放在内存低址部分 用户区:除系统区以外的全部内存空间,提供给用户使用。 最简单的一种存储管理方式,只能用于单用户、单任务的操作系统中。 ...

Marvin_Huoshan的博客 2508

iOS/OS X内存管理(一):基本概念与原理

iOS/OS X内存管理(一):基本概念与原理 发表于14小时前| 546次阅读| 来源优快云| 5 条评论| 作者刘耀柱 移动开发iOSObjective-C内存管理内存泄露局部变量开发经验 摘要:内存管理是在程序需要时程序员分配一段内存空间,而当使用完之后将它释放。如果程序员对内存资源使用不当,有时不仅会造成内存资源浪费,甚至会导致程序crach。本文作者从基本概念开始

周红伟讲AI 1411

探索OS的内存管理原理

从最简单的内存管理原理说起,带大家一起窥探OS的内存管理机制,由此熟悉底层的内存管理机制,写出高效的应用程序

ruanrunxue的博客 874

os-内存管理(基本分页存储管理方式)

文章目录1.1 内存管理1.2 内存管理的功能1.3非连续配置管理方式1.3.1 基本分页存储管理方式1.3.1.1 分页存储的几个基本概念1.3.1.2 基本地址变换机构1.3.1.3 具有快表的地址变换机构1.3.1.4 两级页表1.3.2 基本分段存储管理方式1.3.2.1 分段存储的几个基本概念1.3.2.2 地址变换机构1.3.2.3 段的共享与保护1.3.3 段页式管理方式 1.1 内...

LN-Curiosity 1435

OS之内存管理 ---基本的内存管理策略(一)

基本概念 基本硬件 CPU可以直接访问的通用存储只有内存和处理器的内置的寄存器。机器指令可以用内存地址作为参数,而不能用磁盘地址作为参数。所以执行指令以及指令使用的数据,应在这些可执行访问的存储设备上,如果数据不在内存中,那么在CPU使用他们之前应把数据移到内存上。 CPU内置寄存器通常可以在一个CPU时钟周期内完成访问,但是对于内存,完成内存的访问...

weixin_30478923的博客 340

Xcode 如何设置 自动内存管理 转换为 手动内存管理

建议使用自动内存管理 ARC. 如果不想自动内存管理,可以在build phases 下的compile sources 中找到不想自动管理的.m文件 ,给它加compiler flags 为 -fno-objc-arc刚开始学习Objective-c编程的朋友都希望学习内存管理,但Xcode4.6.3以后的版本就没有了Automatic Reference Counting  (ARC)选项...

weixin_33701294的博客 328

【UCOSIII】【OS内存管理】内部SRAM64K、外部SRAM1M、OSMemGet、OSMemPut

 学习STM32也会遇到这样的绝对定位的问题如下:uint8_t   UART_RX_BUF[1024]   __attribute__ ((at(0X20001000)));   //就是将串口接收的数据定位到RAM中起始地址为0X20001000;绝对定位要么定位到flash、要么定位到RAM,这里我们将定位在flash进行说明通过上面的分析可以看出 UCOSIII 的内 存管理很粗糙,不灵活...

qq1518572311的博客 1674

内存管理——Xcode升级到8.0之后内存管理需要注意的事项

今天回顾复习一下内存管理的知识点,发现了一个不可思议的问题,拿出来和大家一起分享。 在之前我们总是认为是这样的: 引用计数的工作原理: 1.当我们创建(alloc)一个新对象A的时候,它的引用计数从零变为 1; 2.当有一个指针指向这个对象A,也就是某对象想通过引用保留(retain)该对象A时,引用计数加 1; 3.当某个指针/对象不再指向这个对象A,也就是释放(release)该引用

moqj_123的专栏 1003

理解 iOS 和 macOS 的内存管理

在 iOS 和 macOS 应用的开发中,无论是使用 Objective-C 还是使用 swift 都是通过引用计数策略来进行内存管理的,但是在日常开发中80%(这里,我瞎说的,8020 原则嘛

weixin_33763244的博客 277

【操作系统基础】OS管理内存的前置知识

初始内存(main memory) 内存也是叫主存;内存是由一大段的字节序组成的,最关键的一点是这里每一个字节都有一个自己的地址; 在计算机中,CPU是从内存的PC寄存器中获取指令地址来执行程序的; 我们对内存的操作无非就是写入和读取,都是对内存的操作,如何操作内存呢?那就是操作它的地址,比如写入数据到内存,只需要找到你要写入内存的地址就可以达成目标; 对于典型的指令执行周期来说:就是三部曲:CPU取指令form memory,CPU译码指令并且需要一些内存而外数据帮助译码;CPU执行执行,结果返回给内

呋喃吖的博客 634
上一篇: iOS单元测试断言汇总
下一篇: 用dispatch_once实现单例模式
大胖子runner
博客等级 码龄11年 0粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值