Java内存回收

Java提高——Java的内存回收(1) Java引用的种类 当程序员通过new关键字创建对象,即视为为Java对象申请内存空间。JVM会在堆内存中为每个对象分配空间;当一个对象失去引用的时候,JVM垃圾回收机制会自动清除他们,并回收他们所占用的内存空间。 Java内存管理包括内存分配(创建Java对象的时候)和内存回收(回收 Java对象的时候)两个方面。 JVM垃圾回收机制是否回收一个对象的标准:是否有引用变量引用该对象?  ... 阅读详情

好记忆不如按烂笔头 ,写下了,可以温故而知新。

虚拟机内存分区

java虚拟机运行在受不同操作系统操纵的物理机上,不同的操作系统使用不同的底层方法来执行不同的操作,这些方法称之为本地方法:Native Method,本地方法一般执行的都是比较底层的操作,比如说IO、线程管理等,java方法则会执行的一般是相对高级的操作,比如说数逻运算,或者是调用底层的本地方法来完成底层任务。

java虚拟机的运行时数据区域将内存分成了不同的部分协调完成java虚拟机的内存数据交互。

clipboard.png

按照数据存储过程的数据结构可以大致分为:

栈区:

  • 虚拟机栈:java虚拟机运行的java方法(java字节码方法)构成的栈空间,这个空间在运行时存储这些方法的局部变量表、操作栈、动态链接和方法出口;

  • 本地方法栈:本地方法在运行时存储数据产生的栈区。

堆区:

  • java堆:对象的实例存储在这个共享的堆空间里,由于占有最大的和最有实际意义的空间,这个空间的GC过程时虚拟机运行的重点。

  • 方法区:存储虚拟机运行时加载的类信息、常量、静态变量和即时编译的代码,因此可以把这一部分考虑为一个保存相对来说数据较为固定的部分,常量和静态变量在编译时就确定下来进入这部分内存,运行时类信息会直接加载到这部分内存,所以都是相对较早期进入内存的。

  • 运行时常量池:不是所有的常量都是在编译时就确定下来进入内存的,仍然会有运行时才进入内存的常量,这部分常量一般是编译时产生的一些固定信息,比如说翻译出的引用等,直接在类加载的时候把它们存入运行时常量池有助于提高性能。
    所有的内存区域的数据交互由程序计数器指导虚拟机完成复杂的逻辑步骤。

如何找到一个对象的实例:

Object obj = new Object();

在这个过程中在虚拟机栈的局部变量表里创建obj引用,在堆内存里创建Object类的一个实例,最后就是把obj引用和这个对象实例关联起来的问题了,另外,我们需要知道的是,不是所有的实例都完整地保存了所有的类的信息,一般共有的或者静态的类的数据将被保存在方法区中,独有的实例数据才会真的被保存在java堆里,因此每个引用必须同时找到关联它的实例数据和类数据。针对这个问题,有两个办法来做:
clipboard.png
I. 引用存储的只是实例的句柄,句柄在堆的句柄池中,句柄中保存着到堆中真正实例的地址和到方法区中类数据的地址,这样就可以通过这个句柄可以找到这些地址。

clipboard.png

II. 引用存储的就是实例在堆中的地址,而实例中是含有可以定位类数据的地址的,也就是通过找到的实例地址可以再去寻找它对应的类的数据。

两个和内存溢出相关的异常:

  • StackOverflowError:线程申请的栈深度大于虚拟机的规定值;

  • OutOfMemoryError:线程扩展增加的内存大于虚拟机的要求;

内存回收机制

虚拟机栈、本地方法栈和计数器大都是编译期确定的内存分配,在线程执行完毕后即会清理,内存回收相对比较容易。所以我们提到的内存回收大都是指堆内存的回收。我们通过如下几个问题来说明内存回收机制:

1. 什么样的堆内存是可以回收的呢?

什么样的堆内存是可以回收的呢?简而言之就是那些“没用”的内存,那么怎样的内存是“没用”的呢?即那些通过现有的指针(或称“引用”)条件下再也访问不到的内存对象。所以有这样的算法来描述无效的引用:
(引用计数算法)每个对象都有一个被引用计数器,被引用一次计数器加1,引用被置空时减1,最终被引用计数器的值为0 的即是“无用”的内存对象,它占用的内存可以被回收。
(这个算法看起来好像没有问题,但是遭遇到循环引用的时候就会出现问题:如果同时将循环引用的双方置空,那么即使被引用计数器不为0也再也访问不到这些对象了,即发生了内存无故占用)。

clipboard.png

clipboard.png

这个过程体现了互相循环引用可能带来的问题,对象仍被引用但是已经不能被访问了,所以是这种算法的缺陷。

(根搜索算法)将由栈内存或方法区引用的对象作为GCRoots去构建引用链,如果能找到这个对象则说明这个对象能够访问其内存不能被回收,反之通过这些引用链找不到这个对象则说明已经是弃用的对象了,其内存是应该被回收的。(上面的互相循环引用的例子就可以解决了,因为这个问题里面虽然其被引用计数器的值不为0,但是已经没有GCRoots能够找到这些内存了,这个问题里的GC Roots是栈内存里的objA和objB,这两个栈内存里的引用被置空,因此引用链里没办法再找到对内存里的对象了。)

2. 确定了有哪些内存该被回收后GC机制是直接回收内存吗?

确定了有哪些内存该被回收后GC机制是直接回收内存吗?GC会给这些内存中的某些对象一次机会,就是那些重写过finalize方法的类的对象,GC会执行这个对象重写过的finalize方法,如果在这个方法中对象重新将自己链接给了某个引用使得这块内存区域重新可以被访问,那么GC就不会在这次回收它,但是,这个过程只能执行一次,下一次再被GC遇到的话就不会顾及这个finalize方法而是直接回收了,因此要注意重写的finalize方法只能执行一次。
这个是堆内存中对象的回收,在方法区里保存类信息和常量池的内存同样需要回收,这个过程相对来说更缓慢也并没有那么高效,因为一段时间内线程使用的类和常量池都比较稳定,只有当真的确认有类不再使用且不被反射使用的时候才会卸载类,当真的没有常量再被使用的时候才会释放常量池中不用的常量。

3. 内存回收策略和算法是怎样的呢?

知道了哪些内存该被回收、回收前的最后确认之后来说内存回收策略,也就是内存回收的时候究竟是依据什么样的算法进行的?
(标记-清除算法)

clipboard.png

(复制算法)

clipboard.png

(标记-整理算法)

clipboard.png

通过这些算法,jvm可以将已不被引用的无效内存回收,标记-清除算法清理得到的内存往往出现碎片,而标记-整理解决了内存碎片却增加了时间消耗,复制算法则会出现内存浪费的问题,结合不同场景使用不同算法进行垃圾回收是十分重要的。

4. 主流垃圾回收收集器

了解了内存垃圾回收的算法,我们来看执行垃圾回收的垃圾收集器。根据堆内存对对象的代的划分我们对堆内存有这样划分:

clipboard.png

各版本和种类的垃圾回收器各有其用武之地,配合使用它们得到最好的效果十分重要。因为在垃圾内存回收的过程中对每个对象分代处理,所以对不同代的垃圾内存有不同的收集器去回收:创建不久的对象称为新生代,新生代对象的特点即是生死频率高,从生到死的过程很短,所以再回收时有大量的这样的内存存在,所以采用复制算法采用较大的eden:survivor比率将使得内存较完整也较快地回收,同时,老年代的内存存储的是创建很久仍然没有失去引用的对象,这类对象由于长期存在于内存中且未来的生死也常常不确定,所以需要使用速度慢但是更精确地标记-整理算法。下面是真正执行这些回收过程的收集器:
新生代收集器:(主要使用复制算法)

  • Serial收集器:单线程+“Stop the World”停顿式收集

  • ParNew收集器:多线程版本的Serial收集器

  • Parallel Scavenge收集器:多线程收集器,关注“吞吐量”

老年代收集器:(主要使用标记-整理算法)

  • Serial Old收集器:Serial的老年代版本

  • Parallel Old收集器:Parallel的老年代版本

  • CMS收集器:并发收集、低停顿,关注短时间停顿

G1收集器:高级和领先的新型垃圾收集器

5. 内存分配和回收的全过程:

JVM虚拟机将会依次对每次即将进入堆内存的对象做出安排,一定时间间隔内对于失去引用的无效内存进行回收,当内存出现溢出的时候试图通过垃圾回收自发解决问题保持系统回归平稳。

  • 申请内存的对象优先被分配到堆内存的Eden区,如果Eden区的空间不足就向survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,在这次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去(这种现象是对垃圾回收的统计学规律的挑战,因为理论上大多数新生代内存不应该存活到这个时候,所以这个时候就会引发这种叫做分配担保机制的对象向老年代转移),如果存在失去引用的内存,那么就将剩余存活的对象移往survivor区,剩下的Eden区内存全部清理。

  • 大对象直接进入老年区,上面的描述中我们已经可以看到大的对象在一旦出现长时间存活的时候会引发分配担保机制进入老年区,所以不如直接在刚开始创建这个对象的时候就把它放入老年区。

  • 长期存活的对象直接进入老年区:同上面的描述,长期存活的对象的移动会耗费资源,所以在创建这些长期存活的对象时就将它直接放入老年区。

  • 动态对象的年龄判断:虚拟机并不是一直等待所有的对象都到达老年代的标准才将它们放入老年期,因为那样做可能会使新生代的空间一直很紧张引发不必要的GC,所以在当Survivor区里的对象中相同年龄的对象的大小达到Survivor区的一半时就可以将其移入老年区。

  • 空间分配担保:当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。

6.一个借助VisualVM工具探查JVM内存管理的实例

这里我们使用一个实例借助VusualVM来查看程序运行过程中的虚拟机内存分配的过程:
在这个例子中,各种参数均使用默认值:

public class VMTest {
    private static final int _1MB = 1024*1024;
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(4000);
        byte[] allocation1;
        for (int i = 0; i < 400; i++) {
            allocation1 = new byte[_1MB];    
            System.out.println("Create One"+i);
            Thread.sleep(1000);
        }
        
    }
}

这个例子中,主线程每次循环向虚拟机申请内存创建新对象,然后在循环结束的时候将引用链接到新的对象,原来的对象就会处于失去引用的状态,每隔一段时间后JVM的minor GC就会使得这些弃用的对象占据的内存被回收。以下即是这个过程中VisualVM展示的的实时内存各区占据情况:

clipboard.png

这个过程中,我们可以清楚地看出内存分配的全过程。新的对象作为新生代对象会被分配到新生区的Eden区中,在一个循环中这些对象都会被分配到Eden区中,因为Eden区默认的超过600M的空间足够容纳这些对象,当一段时间后发生minor GC的时候就会将仍然存活的(也就是仍然有有效引用的)对象移至空的Survivor区,在这里是Survivor0区,失去引用的对象占据的Eden区空间将会被回收;下一次monor GC到来之前仍然会进行这样的空间分配,Eden区中会产生新的对象并有一些对象会失去有效引用,下一次minor GC到来的时候会把Eden区中存活的对象(以及Survivor0中存活的对象)移至空的Survivor区中,这里是Survivor1,并将Eden和Survivor0回收。注意,每次minor GC进行的时候都会将一个Survivor(from Space)置空,并将存活的对象移至空Survivor(to Space)里,如果Survivor(to Space)空间不足,则会引发分配担保机制将这些存活对象移至老年区。


Java的内存回收机制 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险。但是,也正因为内存管理完全由JVM负责,所以也使Java很多程序员不再关心内存分配,导致很多程序低效,耗内存。因此就有了Java程序员到最后应该去了解JVM,才能写出更高效,充分利用有限的内存的程序。 阅读详情

相关推荐

OPC DCOM详细配置方法 - 不关防火墙不换登陆用户

1. 前言   OPC DCOM的设置是实现跨网络OPC通信的基础,现有的一些OPC DCOM配置教程虽然讲解了如何配置DCOM,但没有讲清楚为什么要这么做,而且各个教程涉及的配置方法也不尽相同。   为了彻底搞清楚OPC DCOM的配置过程,我重新做了两台机器的系统,一台是Windows 7 32位,一台是Windows 10 64位,并且重零开始完整的测试了正常运行OPC DCOM所需的最少的...

steventian72的博客 3万+

java内存区介绍

java内存区域结构的介绍

cqq00的博客 1730

如何让 RTX 5090 开启 PCIE P2P 以加速多卡通信

RTX 5090 基于新的 Blackwell 架构。NVIDIA 出于对某些主板兼容性(如 IOMMU、Resizable BAR 策略)的保守考虑,**屏蔽了 5090 的 BAR1 P2P 功能**。 我们需要通过 Patch 驱动源码,强制开启这一隐藏功能。 开启 P2P 后,PyTorch 的集合通信算子(Multi-GPU 训练的核心)延迟显著降低,**All-Reduce 甚至降低了 60% 以上**。

Hi20240217的博客 1708

Java内存区域详解

直接内存是一种特殊的内存缓冲区,并不在 Java 堆或方法区中分配的,而是通过 JNI 的方式在本地内存上分配的。除了 StackOverFlowError 错误之外,栈还可能会出现OutOfMemoryError错误,这是因为如果栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。⚠️ 注意:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束死亡。

qq_45008709的博客 1924

基于 WebGoat 平台的 SQL 注入攻击

基于 WebGoat 平台的 SQL 注入攻击

Labulongdong的博客 3521

SDN — EVPN Overlay 控制面

完成控制面的配置后,当 VxLAN L2 Gateway(e.g. Leaf1)再收到从 Host1 向 Host2 发出的 ARP Request 时,就会先查看自己的 ARP 广播抑制表,发现有 Host2 的 MAC-IP 记录,则直接将 ARP Request 报文中的广播 MAC 地址替换为目的单播 MAC 地址(广播变单播),然后原路 Reply,从而达到 ARP 广播抑制的目的。手动配置的方式虽然简单,但网络中会存在大量的 BUM 洪泛流量,网络扩展性也受到了限制,并不适用于大规模组网场景。

烟云的计算 1857

Java内存分区

java内存分区

m0_46043168的博客 956

ResNet改进(7):添加 SK注意力机制

实现 SK 注意力机制。

2401_82355416的博客 730

java的内存分区

Java虚拟机栈(Java Virtual Machine Stacks):每个线程在创建时都会分配一个Java虚拟机栈,它的生命周期与线程相同。Java虚拟机栈中存储的是方法执行的栈帧,每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、返回地址等信息。程序计数器(Program Counter Register):是一块较小的内存区域,可以看作是当前线程所执行的字节码的行号指示器。方法区(Method Area):用于存储类的信息,包括类的结构信息、静态变量、常量池、方法信息等。

ThinkPet 711

SAP_MM模块库存概览俄罗斯报表简介

本文介绍了SAP MM模块中"库存概览俄罗斯报表"的功能与应用。该报表主要用于查看物料在不同库存地点和类型的库存情况,并满足俄罗斯当地法规要求。文章解释了"俄罗斯报表"可能指代本地化合规库存报表或客户自定义报表,详细说明了事务代码J3RFLVMOBVEDH的操作步骤,包括公司代码、物料编码、日期范围等查询条件,并解释了报表中各字段含义如期初期末库存数量与价值。最后强调在物料分类账处理完成后使用该报表可获得实际库存价值,为SAP用户提供了实用的库存管理参考。

我小时候很黑的博客 1083

Sigrity System Explorer ViaWizard模式进行过孔建模和仿真分析操作指导

点击TVac_lower tdvac_lower,自动跳转到2D时域曲线,查看最小低电平穿过VIL(ac)max电压的延时,结果如下。点击TVac_high tdvac_high,自动跳转到2D时域曲线,查看最小高电平穿过VIH(ac)min电压的延时,结果如下。点击max Vix_Rise,自动跳转到2D时域曲线,查看上升边PN交叉点与参考电压VREF(dc)的偏差,结果如下。Threshold:阈值,软件自带3个模板,default,Tr01,Tr02,本例选择Default。

weixin_54787054的博客 568

Java内存划分详解

堆(Heap)方法区(Method Area)程序计数器(Program Counter Register)Java虚拟机栈(Java Virtual Machine Stack)本地方法栈(Native Method Stack)接下来我们将逐个详细解释这些区域。Java的内存划分和管理是Java编程中的重要概念。了解这些概念有助于我们更好地理解和优化Java程序的性能和稳定性。在实际开发中,我们应该注意避免内存泄漏和内存溢出等问题,确保程序的稳定运行。

m0_61431263的博客 1229

【小白深度教程 1.8】手把手教你使用 Depth Anything V2 估计单目深度,并映射到 3D 点云(含 Python 代码)

我们尝试使用单目深度估计技术(Depth Anything V2),来进行准确的双目深度估计,并将场景转换成 3D 点云,Python 代码在最后。

2401_87064292的博客 5090

java 内存 回收_java内存回收

一、为什么需要垃圾回收如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。二、哪些内存需要回收?哪些内存需要回收是垃圾回收机制第一个要考虑的问题,所谓“要回收的垃圾”无非就是那些不可能再被任何途径使用的对象。那么如何找到这些对象?1、引用计数法这个算法的实现是,给对象中添加一个引用...

weixin_26878995的博客 2300

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java 数组回收_java的内存回收

程序远通过new关键字创建java对象,即视为java对象申请内存空间,Jvm会在对内存中为每个对象分配空间;当一个java对象失去引用时,JVM的垃圾回收机制会自动清除它们,并且回收它们所占的内存空间。对象在内存中的状态:将jvm内存中对象引用理解成一种有向图,把线程对象当成有向图的定点。顶点科大的对象垃圾回收机制不会回收它们;如果某个对象在这个邮箱途中处于不可达状态,认为这个对象不再被引用,接...

weixin_39828331的博客 876

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

java 回收内存_Java内存回收

Java内存回收Java的GC机制是自动进行的,和C语言有些区别需要程序员自己保证内存的使用和回收。下面是小编分享的具体介绍,一起来看一下吧。Java的内存分配和回收也主要在Java的堆上进行的,Java的堆中存储了大量的对象实例,所以Java的堆也叫GC堆。下面主要说一下对于java堆的内存回收 。什么样的内存可以回收判断法1:引用计数方法:每有一个引用指向这个对象,那么这个对象的引用计数+1,...

weixin_33995900的博客 380

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java内存回收机制

C、C++等语言中,内存的分配和释放由程序代码来完成,容易出现由于程序员漏写内存释放代码引起的内存泄露,最终导致系统内存耗尽。 Java代码运行在JVM中,由JVM来管理 堆Heap 内存的分配和回收(Garbage Collection),把程序员从繁琐的内存管理工作中释放出来,更专注于业务开发。Java内存回收工作由标记(识别可回收对象)和回收(释放可回收对象)两个步骤组成。 和程序代码释放内存相比,内存自动管理会占用一部分CPU时间,Stop The World特点回暂停业务程序运行,非常影响执行效率

hequnwang10的博客 6330

java中的强制内存回收_Java的内存回收

一、java引用的种类1、对象在内存中的状态可达状态:当一个对象被创建后,有一个以上的引用变量指向它。可恢复状态:不可达状态:当对象的所有关联被切断,且系统调用所有对象的finalize方法依然没有使该对象变成可达状态,那该对象将永久性的失去所有引用,最后变成不可达状态。2、引用的类型强引用:软引用:弱引用:虚引用:二、java的内存泄露三、垃圾回收机制1、垃圾回收算法串行(Serial)回收和并...

weixin_40000457的博客 789

java 内存回收参数_Java内存回收(垃圾回收)机制总结

一、背景:Java程序员编写程序时,对于新建的对象,当不再需要此对象时,不必去释放这个对象所占用的空间,这个工作是由Java虚拟机自己完成的 ,即内存回收或垃圾回收。二、如何知道一个对象所占用的空间可以回收了呢?1.常用的一种算法是引用计数法,如果一个对象的引用为0了,那就可以回收了。但是对于这种方法致命缺陷,当对象之间存在循环引用的时候,A引用B,B引用A,这样A和B的引用就一直不会为0,那就无...

weixin_30224993的博客 429

java 手动内存回收_Java堆外内存回收原理

原标题:Java堆外内存回收原理DirectByteBuffer简介DirectByteBuffer这个类是JDK提供使用堆外内存的一种途径,当然常见的应用一般不会接触到,即使涉及到也可能是框架(如netty、rpc等)使用的,对框架使用者来说也是透明的。DirectByteBuffer作用堆外内存优势在于IO操作上,能够节省堆内存到堆外内存的拷贝,所以性能更高,看过netty源码的同学应该了解;...

weixin_35778603的博客 737

Java的内存回收机制详解

Java的内存回收机制详解 说到java内存回收机制,就得先说内存回收的意义。 1 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要

YQlakers的博客 1万+

java的Reference与DirectBuffer的内存回收

java的Reference与DirectBuffer内存的自动回收的实现。。。其实比较曲折的折中的方法实现了DirectBuffer的自动回收。。。

fjs的专栏 3766

Java 内存分配和回收

Java 内存分配和回收是 Java 虚拟机 (JVM) 自动进行的关键过程,旨在有效地管理内存,防止内存泄漏,并优化程序性能。

m0_69529796的博客 627

Java 与 C++的内存回收机制

1、C++的内存回收机制 当我们使用new为一个对象分配了空间之后,在这个对象结束使用之后,我们必须人为的去释放这块内存(delete)。 2、Java的内存回收机制 如下边一段代码: public void funTest(){ String str = new String("Hello World!"); }//str 变量的作用域当用new 创建一个Ja

leo115的专栏 4460

下列( )语句关于Java中内存回收的说明是正确的。

下列( )语句关于Java中内存回收的说明是正确的。 A.程序员必须创建一个线程来释放内存 B.内存回收程序允许程序员直接释放内存 C.内存回收程序负责释放无用内存 D.内存回收程序可以在指定的时间释放内存对象 正确答案 C 答案解析 暂无解析 https://www.imdb.com/list/ls085953068/ https://www.imdb.com/list/ls085953068/?ref_=otl_5 https://www.imdb.com/list/ls085953068/?ref_=

kongbin0471的博客 6279
上一篇: JAVA 异常大集合
下一篇: 如何应对研发团队从30人到1000的挑战
supingemail
博客等级 码龄18年 1235粉丝 320原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值