列举一下Java 中常见的垃圾收集器

深入理解Java中的7种JVM垃圾收集器原理【一万字】 虽然常见的垃圾收集算法都是固定的,但是内存回收如何具体进行是由虚拟机所采用的GC收集器决定的,而通常虚拟机中往往不止有一种GC收集器,他们也采用的不同的垃圾收集算法,下面来看看HotSpot中的7种GC收集器。如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。 1 垃圾收集器概述 HotSpot虚拟机的常见垃圾收集器如下: 上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器 阅读详情

前言

垃圾收集机制是 Java 的招牌能力,极大地提高了开发效率。如今,垃圾收集几乎成为现代语言的标配,即使经过如此长时间的发展, Java 的垃圾收集机制仍然在不断的演进中,不同大小的设备、不同特征的应用场景,对垃圾收集提出了新的挑战,这当然也是面试的热点。

本篇博文的重点是,Java 常见的垃圾收集器有哪些?

概述

实际上,垃圾收集器(GC,Garbage Collector)是和具体 JVM 实现紧密相关的,不同厂商(IBM、Oracle),不同版本的 JVM,提供的选择也不同。接下来,我来谈谈最主流的 Oracle JDK。

  • Serial GC,它是最古老的垃圾收集器,“Serial” 体现在其收集工作是单线程的,并且在进行垃圾收集过程中,会进入臭名昭著的 “Stop-The-World” 状态。当然,其单线程设计也意味着精简的 GC 实现,无需维护复杂的数据结构,初始化也简单,所以一直是 Client 模式下 JVM 的默认选项。从年代的角度,通常将其老年代实现单独称作 Serial Old,它采用了标记 - 整理(Mark-Compact)算法,区别于新生代的复制算法。Serial GC 的对应 JVM 参数是:

  • -XX:+UseSerialGC 复制代码

  • ParNew GC,很明显是个新生代 GC 实现,它实际是 Serial GC 的多线程版本,最常见的应用场景是配合老年代的 CMS GC 工作,下面是对应参数

  • -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 复制代码

  • CMS(Concurrent Mark Sweep) GC,基于标记 - 清除(Mark-Sweep)算法,设计目标是尽量减少停顿时间,这一点对于 Web 等反应时间敏感的应用非常重要,一直到今天,仍然有很多系统使用 CMS GC。但是,CMS 采用的标记 - 清除算法,存在着内存碎片化问题,所以难以避免在长时间运行等情况下发生 full GC,导致恶劣的停顿。另外,既然强调了并发(Concurrent),CMS 会占用更多 CPU 资源,并和用户线程争抢。

  • Parallel GC,在早期 JDK 8 等版本中,它是 server 模式 JVM 的默认 GC 选择,也被称作是吞吐量优先的 GC。它的算法和 Serial GC 比较相似,尽管实现要复杂的多,其特点是新生代和老年代 GC 都是并行进行的,在常见的服务器环境中更加高效。开启选项是:

  • -XX:+UseParallelGC 复制代码

另外,Parallel GC 引入了开发者友好的配置项,我们可以直接设置暂停时间或吞吐量等目标,JVM 会自动进行适应性调整,例如下面参数:

-XX:MaxGCPauseMillis=value -XX:GCTimeRatio=N // GC时间和用户时间比例 = 1 / (N+1) 复制代码
  • G1 GC 这是一种兼顾吞吐量和停顿时间的 GC 实现,是 Oracle JDK 9 以后的默认 GC 选项。G1 可以直观的设定停顿时间的目标,相比于 CMS GC,G1 未必能做到 CMS 在最好情况下的延时停顿,但是最差情况要好很多。 G1 GC 仍然存在着年代的概念,但是其内存结构并不是简单的条带式划分,而是类似棋盘的一个个 region。Region 之间是复制算法,但整体上实际可看作是标记 - 整理(Mark-Compact)算法,可以有效地避免内存碎片,尤其是当 Java 堆非常大的时候,G1 的优势更加明显。 G1 吞吐量和停顿表现都非常不错,并且仍然在不断地完善,与此同时 CMS 已经在 JDK 9 中被标记为废弃(deprecated),所以 G1 GC 值得你深入掌握。

正文

垃圾收集的原理和基础概念

第一,自动垃圾收集的前提是清楚哪些内存可以被释放。这一点可以结合我前面对 Java 类加载和内存结构的分析,来思考一下。

主要就是两个方面,最主要部分就是对象实例,都是存储在堆上的;还有就是方法区中的元数据等信息,例如类型不再使用,卸载该 Java 类似乎是很合理的。

对于对象实例收集,主要是两种基本算法,引用计数和可达性分析。

  • 引用计数算法,顾名思义,就是为对象添加一个引用计数,用于记录对象被引用的情况,如果计数为 0,即表示对象可回收。这是很多语言的资源回收选择,例如因人工智能而更加火热的 Python,它更是同时支持引用计数和垃圾收集机制。具体哪种最优是要看场景的,业界有大规模实践中仅保留引用计数机制,以提高吞吐量的尝试。Java 并没有选择引用计数,是因为其存在一个基本的难题,也就是很难处理循环引用关系。

  • 另外就是 Java 选择的可达性分析,Java 的各种引用关系,在某种程度上,将可达性问题还进一步复杂化,具体请参考 【JAVA】强引用、软引用、弱引用、幻象引用有什么区别?,这种类型的垃圾收集通常叫作追踪性垃圾收集(Tracing Garbage Collection)。其原理简单来说,就是将对象及其引用关系看作一个图,选定活动的对象作为 GC Roots,然后跟踪引用链条,如果一个对象和 GC Roots 之间不可达,也就是不存在引用链条,那么即可认为是可回收对象。JVM 会把虚拟机栈和本地方法栈中正在引用的对象、静态属性引用的对象和常量,作为 GC Roots。

方法区无用元数据的回收比较复杂,我简单梳理一下。还记得我对类加载器的分类吧,一般来说初始化类加载器加载的类型是不会进行类卸载(unload)的;而普通的类型的卸载,往往是要求相应自定义类加载器本身被回收,所以大量使用动态类型的场合,需要防止元数据区(或者早期的永久代)不会 OOM。在 8u40 以后的 JDK 中,下面参数已经是默认的:

-XX:+ClassUnloadingWithConcurrentMark 复制代码

第二,常见的垃圾收集算法,我认为总体上有个了解,理解相应的原理和优缺点,就已经足够了,其主要分为三类:

  • 复制(Copying) 算法,我前面讲到的新生代 GC,基本都是基于复制算法,过程就如 【JAVA】Java 常见的垃圾收集器有哪些? 所介绍的,将活着的对象复制到 to 区域,拷贝过程中将对象顺序放置,就可以避免内存碎片化。这么做的代价是,既然要进行复制,既要提前预留内存空间,有一定的浪费;另外,对于 G1 这种分拆成为大量 region 的 GC,复制而不是移动,意味着 GC 需要维护 region 之间对象引用关系,这个开销也不小,不管是内存占用或者时间开销。

  • 标记 - 清除(Mark-Sweep) 算法,首先进行标记工作,标识出所有要回收的对象,然后进行清除。这么做除了标记、清除过程效率有限,另外就是不可避免的出现碎片化问题,这就导致其不适合特别大的堆;否则,一旦出现 Full GC,暂停时间可能根本无法接受。

  • 标记 - 整理(Mark-Compact),类似于标记 - 清除,但为避免内存碎片化,它会在清理过程中将对象移动,以确保移动后的对象占用连续的内存空间。注意,这些只是基本的算法思路,实际 GC 实现过程要复杂的多,目前还在发展中的前沿 GC 都是复合算法,并且并行和并发兼备。

注意,这些只是基本的算法思路,实际 GC 实现过程要复杂的多,目前还在发展中的前沿 GC 都是复合算法,并且并行和并发兼备。

垃圾收集过程的理解

在 【JAVA】Java 常见的垃圾收集器有哪些? 对堆结构进行了比较详细的划分,在垃圾收集的过程,对应到 Eden、Survivor、Tenured 等区域会发生什么变化呢?

这实际上取决于具体的 GC 方式,先来熟悉一下通常的垃圾收集流程,我画了一系列示意图,希望能有助于你理解清楚这个过程。

第一,Java 应用不断创建对象,通常都是分配在 Eden 区域,当其空间占用达到一定阈值时,触发 minor GC。仍然被引用的对象(绿色方块)存活下来,被复制到 JVM 选择的 Survivor 区域,而没有被引用的对象(黄色方块)则被回收。注意,我给存活对象标记了“数字 1”,这是为了表明对象的存活时间。

​第二, 经过一次 Minor GC,Eden 就会空闲下来,直到再次达到 Minor GC 触发条件,这时候,另外一个 Survivor 区域则会成为 to 区域,Eden 区域的存活对象和 From 区域对象,都会被复制到 to 区域,并且存活的年龄计数会被加 1。

​第三, 类似第二步的过程会发生很多次,直到有对象年龄计数达到阈值,这时候就会发生所谓的晋升(Promotion)过程,如下图所示,超过阈值的对象会被晋升到老年代。这个阈值是可以通过参数指定:

-XX:MaxTenuringThreshold=<N> 复制代码

​后面就是老年代 GC,具体取决于选择的 GC 选项,对应不同的算法。下面是一个简单标记 - 整理算法过程示意图,老年代中的无用对象被清除后, GC 会将对象进行整理,以防止内存碎片化。

​通常我们把老年代 GC 叫作 Major GC,将对整个堆进行的清理叫作 Full GC,但是这个也没有那么绝对,因为不同的老年代 GC 算法其实表现差异很大,例如 CMS,“concurrent”就体现在清理工作是与工作线程一起并发运行的。

GC 的新发展

GC 仍然处于飞速发展之中,目前的默认选项 G1 GC 在不断的进行改进,很多我们原来认为的缺点,例如串行的 Full GC、Card Table 扫描的低效等,都已经被大幅改进,例如, JDK 10 以后,Full GC 已经是并行运行,在很多场景下,其表现还略优于 Parallel GC 的并行 Full GC 实现。

即使是 Serial GC,虽然比较古老,但是简单的设计和实现未必就是过时的,它本身的开销,不管是 GC 相关数据结构的开销,还是线程的开销,都是非常小的,所以随着云计算的兴起,在 Serverless 等新的应用场景下,Serial GC 找到了新的舞台。

比较不幸的是 CMS GC,因为其算法的理论缺陷等原因,虽然现在还有非常大的用户群体,但是已经被标记为废弃,如果没有组织主动承担 CMS 的维护,很有可能会在未来版本移除。

如果你有关注目前尚处于开发中的 JDK 11,你会发现,JDK 又增加了两种全新的 GC 方式,分别是:

  • Epsilon GC,简单说就是个不做垃圾收集的 GC,似乎有点奇怪,有的情况下,例如在进行性能测试的时候,可能需要明确判断 GC 本身产生了多大的开销,这就是其典型应用场景。

  • ZGC,这是 Oracle 开源出来的一个超级 GC 实现,具备令人惊讶的扩展能力,比如支持 T bytes 级别的堆大小,并且保证绝大部分情况下,延迟都不会超过 10 ms。虽然目前还处于实验阶段,仅支持 Linux 64 位的平台,但其已经表现出的能力和潜力都非常令人期待。

当然,其他厂商也提供了各种独具一格的 GC 实现,例如比较有名的低延迟 GC,Zing 和 Shenandoah 等;

后记

以上就是文章的所有内容了,从整体上梳理了目前的主流 GC 实现,包括基本原理和算法,并结合我前面介绍过的内存结构,对简要的垃圾收集过程进行了介绍,希望能够对你的相关实践有所帮助。

Java 的七种垃圾收集器 用C或C++这样的编程语言写一个应用时,需要编写代码来销毁内存中不再需要的对象。当应用程序扩展得越来越复杂时,未使用对象被忽略释放的可能性就越大。这会导致内存泄露,最终内存耗尽,在某个时刻将没有更多的内存可以分配。结果就是应用程序运行失败并出现OutOfMemoryError错误。但在Java中,垃圾收集器GarbageCollection(GC)会在程序执行过程中自动运行,减轻了手动分配内存和可能的内存泄漏的任务。... 阅读详情

相关推荐

七大经典垃圾回收器篇+部分调优 不会让你失望(两万字)【图文】

文章目录一、垃圾回收器分类二、评估GC的性能指标三、吞吐量 VS 暂停时间四、垃圾回收器发展史五、七大经典的垃圾回收器 一、垃圾回收器分类 1、按垃圾回收线程数分,可以分为串行垃圾回收器和并行垃圾回收器。 (1)串行回收指的是在同一时间段内只允许有一个CPU用于执行垃圾回收操作,此时工作线程被暂停,直至垃圾收集工作结束。 ➢在诸如单CPU处理器或者较小的应用内存等硬件平台不是特别优越的场合,串行回收器的性能表现可以超过并行回收器和并发回收器。所以,串行回收默认被应用在客户端的Client模式下的JVM中。6

qq_43012792的博客 1万+

17_1_垃圾回收器_GC分类与性能指标、概述、Serial、ParNew、Parallel、CMS、面试

垃圾回收器1、GC分类与性能指标1.1、GC分类1.2、评估GC的性能指标2、不同的垃圾回收器概述2.1、垃圾回收器的发展2.2、7款经典的垃圾收集器及其与垃圾分代的关系2.3、垃圾收集器的组合关系2.4、查看默认的垃圾回收器3、Serial、SerialOld 回收器:串行回收(了解)4、ParNew回收器:并行回收(了解)5、Parallel、ParallelOld:吞吐量优先6、CMS回收器:低延迟 1、GC分类与性能指标 1.1、GC分类 按线程数分(垃圾回收线程数),可以分为串行垃圾回收器和

root_zhb的博客 1153

变压器励磁电感、励磁电流、漏感、漏感折算

励磁、漏感知识整理

HW-BASE的博客 1万+

Java中常用的垃圾回收器

JVM中常见的几种垃圾回收器(Parallel、CMS、G1)

一名后端程序猿 5027

在工作台 LS-DYNA 中检索和变换反作用力分量

在结构仿真中,通常需要由施加的位移或速度边界条件产生的反作用力。此外,通常需要根据用户定义的坐标系解析反作用力分量。在本文中,详细介绍了在Workbench (WB) LS-DYNA 中,相对于用户定义的坐标系检索和变换反作用力分量的过程。

jkh920184196的博客 886

django安装mysqlclient (Windows下正确安装mysqlclient)

由于本人也是初学Python和django。本人使用的Python版本是3.7所以连接MySQL数据库需要安装数据驱动,对应Python3的数据驱动是mysqlclient。因此本人习惯性的使用命令pip install mysqlclient,结果安装失败 (venv) C:\Users\songlihui\PycharmProjects\autotest&gt;pip install my...

songlh1234的博客 2万+

Java面试题:列举并解释JVM中常见的垃圾收集器,并比较它们的优缺点

每种垃圾收集器都有其特定的使用场景和优缺点,选择合适的垃圾收集器需要根据应用的特点和需求来决定。例如,对延迟敏感的应用可能更倾向于使用CMS或G1收集器,而对吞吐量有较高要求的应用可能更适合Parallel Scavenge或Parallel Old收集器。在JVM中,垃圾收集器(Garbage Collector, GC)是内存管理的关键部分,负责回收不再使用的对象,释放内存资源。

杰哥在此的专栏 249

从零抓包分析AVDTP:用Wireshark解密蓝牙音频传输全流程

本文详细介绍了如何使用Wireshark抓包工具分析AVDTP协议,解密蓝牙音频传输的全流程。从实验环境搭建到信令交互解析,再到媒体流传输深度分析,逐步揭示蓝牙音频传输的技术本质,帮助开发者深入理解AVDTP协议的工作机制。

sun99的博客 204

如何查看JDK使用的垃圾收集器

如何查看JDK使用的垃圾收集器

一起coding,一起嗨。 1430

人形机器人大语言模型 pi*0.6(π*0.6):最新从经验中学习的VLA

摘要:本文介绍了一种名为Recap的机器人学习方法,通过示范训练、纠错指导和强化学习三个步骤提升机器人执行复杂任务的能力。研究显示,仅依靠模仿学习的机器人难以解决错误累积问题,而Recap方法通过价值函数可视化和优势条件策略训练,使π*0.6模型在咖啡制作、纸箱组装和衣物折叠等任务中的成功率提升超过90%,吞吐量翻倍。该方法突破了传统依赖人工演示的局限,通过自主经验学习实现机器人性能的持续优化,为未来机器人基础模型的发展提供了新方向。

2506_90492529的博客 1321

【气候极端指数】MATLAB计算各种气候极端指数

简介各类气候极端指数,及其MATLAB计算代码

WW、forever的博客 4918

如何选择垃圾收集器?

请注意,以上内容并非全部适用于所有场景,您需要根据自己的实际情况进行选择。同时,也可以咨询专业的技术人士以获取更准确的建议。

qq_33240556的博客 565

深度解析:LPDDR5 采样 Mask 背后的秘密 —— 从 Jitter 到 BER 全面剖析

在 LPDDR5 中,CK/DQS 信号相当于“指挥棒”,而数据(DQ)要在时钟节拍里被准确采样。Crosspoint Mask 区域横轴:时间 (Time)纵轴:电压 (Vref)👉 只要采样点落在这个区域内,数据就是正确的。否则就会出错。BERPBERPMask 就像高速公路的收费站口,如果车(采样点🚗)在车道内,顺利通过;一旦跑偏,就撞护栏。LPDDR5 的速率极高,UI 非常短,Mask 区域成为核心指标各种 Jitter、Noise 会不断压缩 Mask。

weixin_43199439的博客 354

第3章 垃圾收集器与内存分配策略《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》

Java世界中的所有对象实例,垃圾收集器进行回收前就是确定对象哪些是的,哪些已经。

输入知识,消化知识,输出知识,分享知识,教人让我学习更好,业精于勤荒于嬉,行成于思毁于随 1564

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

怀旧版电脑GBC模拟器

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

92-java 分代回收算法

Java的垃圾收集器使用了分代垃圾收集策略,这是基于这样一个假设:不同的对象的生命周期是不一样的。年轻代(Young Generation)、老年代(Old Generation)和永久代(Perm Generation,在Java 8中被元数据区取代)在这个例子中,我们创建了一个新的Object对象,然后将它的引用设置为null,这样这个对象就不再被任何活动线程引用,符合垃圾收集的条件。方法,通知JVM执行垃圾收集,但是具体何时发生垃圾收集是不确定的,取决于JVM的垃圾收集策略和运行环境。

weixin_41775999的博客 454

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java gc实例_java中gc算法实例用法

在我们对gc中的算法有基本概念理解后,要把算法的理念实现还需要依托实际垃圾收集器的使用。因为光靠一些简单的原理不足以支撑整个程序的运行,在回收机制上有专门的收集器。下面我们就垃圾收集器的概念、使用注意事项、收集器图解进行介绍,然后带来两种常见的垃圾收集器供大家参考。1.概念垃圾收集器时之前列举的垃圾收集算法的具体实现。2.注意事项每一个回收器都存在Stop The World 的问题,只不过各个回...

weixin_30407563的博客 257

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

剑指Java面试-Offer直通车--GC

前言:以下相关内容多为图片,参考链接、附上少量文字解释,以便整理脉络,以作复习巩固之用。若需详细了解,请查阅相关资料或者观看相关课程。如有错误,敬请指出,谢谢。 GC一、垃圾回收之标记算法引用计数算法可达性分析算法二、回收算法1、标记-清除算法(Mark and Sweep)2、复制算法(copying)3、标记-整理算法(Compacting)4、分代收集算法(Generational Collector)分代收集算法关键词三、常见的垃圾收集器JVM的运行模式:垃圾收集器之间的联系 参考链接:《剑指Jav

weixin_43271235的博客 852

java内存漏洞_Java中存在的内存漏洞问题与处理

科技信息 0计算机与信息技术0 SCIENCE&TECHNOLOGY INFORMATION 2007年 第 3l期Java中存在的内存漏洞问题与处理吴万琴f甘肃联合大学理工学院 甘肃 兰州 730000)【摘 要 java语言中,其内存管理工作是由一个后台垃圾自动收集 (Garbage couector)完成的,但在java编程中,仍然存在这内存漏洞,内存管理仍旧是要考虑的问题,在本文中,您将了...

weixin_39960147的博客 226

java中的JVM垃圾处理机制_jvm的垃圾回收机制

一、jvm内存的分区JVM的内存结构包括五大区域:程序计数器、虚拟机栈、本地方法栈、堆区、方法区。其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生、随线程而灭,因此这几个区域的内存分配和回收都具备确定性,就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。而Java堆区和方法区则不一样,这部分内存的分配和回收是动态的,正是垃圾收集器所需关注的部分。垃圾收集器在对堆...

weixin_34092535的博客 249

Java虚拟机(JVM)内存管理

Java 虚拟机 (JVM) 是运行 Java 字节码的虚拟机环境。理解 JVM 如何管理和优化内存对于编写高效且可靠的 Java 应用程序至关重要。由于 Java 采用自动垃圾收集机制,因此开发人员无需手动释放内存。垃圾收集器会自动检测不再使用的对象,并释放它们占用的内存。堆内存是 JVM 中最大的一块内存区域,也是垃圾收集器管理的主要区域。堆被进一步划分为新生代和老年代。JVM 将内存划分为几个不同的区域,每个区域都有特定的用途和生命周期。

weixin_42564451的博客 2119

java平台的理解及垃圾收集

title: 每日深耕,勤练不缀 有一个想法,就是将自己每天对技术的感悟写下来,有时候我们弄通一个小技术,感觉太丢人了,这么小的东西怎么写。但是我就要写,因为我以后会用到,大家以后也会用到。 前言 每个java小白都会遇到的阵痛,我写下来。 一句古语:秦人不暇自哀而后人哀之,后人哀之而不鉴之,亦使后人复哀后人也。 一、1.谈谈你对java平台的理解? 书写一次,到处执行。 1.Javac编译成为字节码,再通过JVM内嵌的解释器将字节码转换为最终的机器码 2.JVM会通过类加载器(class .

qq_42762824的博客 125

jvm垃圾回收机制查看及说明

jvm垃圾回收机制

qq_41451744的博客 4878

探索 Java 垃圾收集:对象存活判定、回收流程与内存策略

Java 的垃圾收集机制是通过自动管理内存来减轻开发者的负担,它包括。

wangjinjin180的博客 563

Java JVM 垃圾回收算法详解

JVM 的垃圾回收机制是 Java 程序高效运行的重要保障。了解和掌握垃圾回收的原理、算法和常见收集器,能够帮助开发者优化 Java 应用的性能。在实际项目中,通过选择合适的垃圾收集器并进行合理的调优,可以最大限度地提高内存利用率,减少 GC 带来的性能影响。

萌萌白白的博客 1084

JVM:垃圾收集器与内存分配策略

判断对象是否存活 引用计数法:强引用->软引用(内存溢出异常前第二次回收)->弱引用->虚引用 可达性分析算法:一个对象到GC Roots没有任何引用链(Reference Chain),则证明此对象不可用 无用的类标准 该类所有的实例都已回收 加载该类的ClassLoader已被回收 Class没有在任何地方被引用,及反射 ...

weixin_30800807的博客 66
上一篇: JAVA缓存规范—JCache API与Spring Cache
下一篇: 谈一谈Redis是不是单线程和它快的原因
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值