MAT 工具使用详解

2012年11月29日
1

介绍

移动平台的开发是严格与内存管理有关。虽然技术进步使移动设备的存储容量达到低端台式机的水平,由开发商提出的申请也增长比例。在设备的屏幕尺寸主要问题在于 - 更高的对角线意味着更高的图形分辨率的使用和更高的内存需求。开发人员所熟悉的Andr​​oid平台也知道垃圾回收器不会完全保护应用程序的内存泄漏。这是不难想象对性能的影响,如果发生这种情况,一个大的,动态的应用程序。这就是为什么优秀的内存分析技能是开发必不可少的。本文将介绍一些有用的工具和实践来检测关键的内存泄漏。

工具

有许多工具可以帮助识别内存泄漏。下面是一个示例列表,这些工具的简要说明:

产品名称: 说明:
DDMS(Dalvik的调试监控服务器) 调试工具运了Android。提供端口转发服务,屏幕捕捉,线程信息,堆转储和信息,logcat中,过程和无线电状态信息和更多的功能。可以使用“。/ DDMS”命令在命令行启动。同时它集成到Eclipse IDE中(DDMS透视)。
MAT(内存分析工具) 快速的Java堆分析仪,帮助查找内存泄漏和减少内存消耗。这是一个非常强大的工具,解析堆转储并对其进行分析。它是如此的丰富功能,这是很难列出的所有功能。有一个独立版本和共同商定的一个Eclipse插件。有关安装的详细信息,请参阅本链接
命名法

内存分析必然会有许多专用术语。由于这些将会经常在这篇文章中出现,这里是他们的定义:

期限: 定义:
堆大小 分配给Java堆内存。在Android平台上它是有限的每项活动(取决于设备)。
堆转储 它包含有关您的堆对象信息的二进制文件。
支配树 图中使用(在这种情况下),以呈现对象之间的关系。请参见(维基)的更多细节。
内存泄漏 有泄漏时,有一个参照是防止该对象被垃圾收集未使用的对象。一个对象可以具有一个参照束的其他对象和一个单一的参考可以防止大量对象的垃圾收集。需要记住的最重要的事情是让GC不会阻止内存泄漏!
GC根 GC根是被认为是可到达的对象。通常,这些包括由系统类加载器加载当前的调用栈和类引用的所有对象。
内存泄漏

有泄漏时,有一个参照是防止该对象被垃圾收集未使用的对象。一个对象可以有一个参照束的其他对象和单个基准可以防止GC进行大量的对象。

图。 1

图。1

浅堆

内存由一个对象所消耗。

例如:

公共final类 myObject的{ / /头:8字节
  私人INT 值a;  / / INT:4字节
  私人诠释  valueB;  / / INT:4字节
  字符私人  valueC []  / /字符:4字节 
}

myObject的总浅大小为20字节。

保留堆

的,可以通过释放一个对象被释放的对象总大小。

GC之前:GC将运行在对象A

图。 2

图。2

GC后:释放对象A(300字节),将导致释放对象B(50字节)和C(50字节)。还通过释放对象B,对象D(100字节)将被垃圾收集。因此,通过收集对象A - GC将能够释放500字节(浅堆的总和),这是保留的堆。

图。 3

图。3

检测内存泄漏

有几种方法来发现内存泄漏。本节将介绍这样做的几种方法。

logcat的消息

发现一个内存泄漏的第一种方法是检查logcat的输出。当垃圾收集器开始工作它把消息转换为logcat的输出。它看起来应该像这样:

D / dalvikm(14302):GC_CONCURRENT释放2349K,65%无3246K/9551K,外部4703K/5261K,暂停2ms的2毫秒

消息的第一部分表示GC的类型(原因GC的)。有四种不同类型:

类型 描述
GC_CONCURRENT 当堆变得太大,以防止溢出时调用。
GC_FOR_MALLOC 调用时GC_CONCURENT时间没有运行,应用程序必须分配更多的内存。
GC_EXTERNAL_ALLOC 用于蜂窝前进行外部释放分配的内存。在蜂窝和更高没有外部分配。
GC_EXPLICIT 当的System.gc调用时调用。

“解放2349K,” - 表示内存是多大的释放。

“65%自由3246K/9551K” - 表示的剩余空间百分比,活动对象的大小和总堆大小。

“外部4703K/5261K” - 表示外部内存分配,有多少外部存储器的应用程序已分配和分配的软限制。

“顿了顿2ms的2毫秒” - 表示多少时间花费在GC完成收集。

有了这些信息,可以经过几集,告诉如果GC被成功释放内存。如果分配的内存不会一段时间之后下去(而且还在不断增加),很显然是有内存泄漏。这里是一个相当微不足道泄漏的例子:

图。 4

图。4

的OutOfMemoryError异常

当可用资源耗尽了内存不足错误异常。这可能表明存在内存泄漏。此方法不知道是否有因为当开发人员尝试分配大量的内存(如位图),总堆大小将超过该平台的限制,可能会出现异常泄漏的最佳方式。它肯定表示,开发商应该反思一下自己的内存管理方法。

跟踪内存分配

在成功诊断内存问题现在是时候寻找病因是什么。有两个工具将在分析应用程序的帮助。

DDMS

DDMS是一个强大的工具,可以提供有价值的信息,并用于MAT一个HPROF内存转储文件。从Eclipse IDE中选择窗口 - >打开透视图 - > DDMS DDMS访问。

图。 5

图。5

该接口是相当多的自我解释所以没有必要进入描述它的细节,但有两个选项卡,可能会有所帮助。其中第一个就是“分配跟踪器”显示当前分配,如分配的班级,分配大小和分配的内存位置的详细统计信息。

图。 6

图。6

第二个被称为“堆”。大约有多少每个类的对象被分配在内存和详细信息的实际大小。

图。 7

图。7

倾销HPROF文件很容易。连接设备,运行应用程序,使用了一段时间,然后点击“转储HPROF文件”按钮位于工具栏的设备选项卡上。如果已经安装了MAT插件,Eclipse会自动打开该文件。

内存分析工具(MAT)

MAT是一个非常强大的内存分析工具。它可以作为一个独立的版本,或作为一个Eclipse插件。这两者之间唯一的区别是它们如何处理加载HPROF文件。单机版需要一个转换的HPROF文件。这可以通过使用附带的Andr​​oid SDK(定位于工具文件夹中)的HPROF-CONV程序来实现。在使用该插件的版本就没有必要将文件转换。要打开MAT选择窗口 - >打开透视图 - >其他 - >内存分析。

概观

加载HPROF文件后,用户呈现总览屏幕。它包括以下元素:

  1. Open概要窗格 - 打开主总览屏幕。
  2. 从任意一组对象的创建直方图 - 从创建对象(在本文后面介绍)直方图视图。
  3. 打开支配树,整个堆 - 打开支配树视图(在后面的文章中介绍)。
  4. 打开对象查询语言工作室 - 一个工具,允许写入MAT查询。
  5. 运行专家系统测试 -
    • 堆转储概述 - 提供有关堆转储文件的详细信息。
    • 泄漏疑点 - 提供如大小,装载机,涉嫌泄密的对象类型的详细信息。
    • 顶部组件 - 提供有关在内存中最大的对象的信息。还包含了可能的内存废弃物的报告。
  6. 打开查询浏览器 - 包含许多有用的查询,帮助分析内存。本指南将介绍一些最有用的。
    • 列表中的对象 - 显示与传入或传出引用的对象(MAT会提示一个对象用于查询)。
    • 显示对象按类 - 列出对象由类排序。
    • 路径GC根 - 显示引用路径的GC根(与许多过滤选项)。
    • 合并最短路径到GC根 - 查找到一个对象或一组对象的垃圾回收根的共同路径。
    • 直接的支配者 - 查找和类级别的所有对象占据一个给定对象的集合体。
    • 显示保留设置 - 计算保留​​一套任意一组对象的。
  7. 查找对象按地址 - 通过提供其地址允许发现一个特定的对象。
  8. 饼图 - 显示保留尺寸最大的对象。
  9. 直方图 - 显示每个对象类的实例的数量。
  10. 10。支配树 - 列表对象中聘请的堆量有组织的系统的实例。
  11. 督察 - 提供有关选定对象的详细信息。
图。 8

图。8

直方图

其中最有用的工具是MAT。它可以列出任何给定类的实例的数量。当寻找一个内存泄漏或内存问题,这是好事,先来看一下最“濒危”类和检查多少实例存在。还有一个非常有用的正则表达式的字段,以允许搜索特定类别。直方图视图还允许在计算最小和精确保留堆选定对象。

  1. 计算保留大小 -
    • 计算最小保留大小 - 计算的最小保留尺寸,并将其显示于下表中。
    • 计算精确保留大小 - 计算精确的保留大小(这个过程可能需要一段时间),并显示在下面的表格。
  2. 正则表达式模式 - 允许用户搜索指定的对象类。
图。 9

图。9

直方图的另一部分是项目的上下文菜单。它允许访问查询(在概述部分所述),将所选对象被调用。这是一个非常重要的工具,当涉及到诊断内存问题。如果有可疑的内存泄漏,开发人员可以检查的具体项目的传入引用,找出哪些是保持被收集。当然,垫还允许过滤从这样的查询(例如,通过限制对象到指定的类)的结果。接收对象的列表从查询后,开发商都带有另外一个有用的工具 - “路径与GC根”。它包含了像不包括弱引用许多过滤选项 - 这是最常见的过滤器之一,因为弱引用不会阻止对象被收集由GC没有必要一一列举。如果用户不满意的预定义查询太让他从头开始定制或编写一个如此有可能性无限多。详情和查询的实际应用将在后面介绍这篇文章。

图。 10

图。10

图。 11

图。11

支配树

支配树是在MAT第二个有用的观点。它列出了保留的堆量有组织的系统对象的实例。它可以从概述,或从指定的对象类的上下文菜单中选择“立即统治者”选项进行访问。前者显示从内存转储,后者的发现和聚合所有支配一组给定的类级对象的对象的所有对象。以下是支配树的一些重要性质:

  1. 属于的“x”的子树中的对象表示保留组“×”。
  2. 如果“x”是的“Y”直接支配,则“x”的直接支配者也占主导地位的“y”。
  3. 在支配树边不直接对应到对象从对象图的参考。

这三个属性是支配树视图的很好的理解非常重要。使用该视图熟练开发人员可以迅速地找到并引用它们是不必要的每个对象的留存堆。

图。 12

图。12

查询

查询是旨在帮助通过对象的森林得到的基本工具。内存分析发现在许多对象的堆栈不需要引用的过程 - 它不是一件容易的事。过滤这些对象和引用使得它更容易。有迹象表明,开发商应该学会成功调试内存中的两个关键技能。第一是自己的应用程序的知识。有没有办法找到一个内存问题,如果找它的人并不知道应用程序的对象结构应该是什么样子。第二个技巧是使用筛选器和查询。如果开发人员知道对象的结构并且知道如何获得理想的观点就很容易发现异常。这里是在MAT内置的查询的列表:

查询: 选项​​: 说明:
列表中的对象 与即将离任的参考资料 表明有一个传出参考所选择的对象的对象。
传入参考 表明有来电参照所选择的对象的对象。[如果有,有很多不必要的实例的类是很好的做法,发现是保持它被GC传入引用]
按类别显示对象 与即将离任的参考资料 列出了有传出参照所选对象并将其按类排序的对象。
传入参考 列出了具有一个输入参考选择的对象,并将它们按类别进行排序的对象。
路径GC根 与所有引用 给出了参考路径从对象对GC根在内的所有引用。
排除弱引用 给出了参考路径从对象对GC根不含弱引用[那些不会用GC保持物体被横扫]
排除软引用 给出了参考路径从对象对GC根不包括软引用。
排除虚引用 示出了参考路径从对象到GC根不含虚引用。
合并最短路径到GC根。 同为“路径GC根” 显示了共同的参考路径,从GC根的对象。
Java基础 参考文献统计类加载器资源管理器 显示统计数据引用和对象。List类加载器,包括其定义的类。
自定义保留设置 计算保留一组对象不包括在查询参数中传递的引用。
开启在支配树 创建一个支配树,所选择的对象。
显示为直方图 显示的任意对象的直方图视图。
线程详细信息 显示线程的详细信息和属性。
线程概述和堆栈 -
Java集合 阵列填充率 打印非原始阵列的填充比的频率分布。
阵列由分组大小 示出了由大小分组阵列的直方图。
收藏填充率 打印给定集合的填充比率的频率分布。
收藏集规模分 显示收藏集大小分组的直方图。
哈希提取设定值 列出选定的哈希集合的元素。
提取列表值 列出选定的LinkedList,ArrayList的或Vector的元素。
哈希条目 提取键 - 值对选定的HashMap和哈希表的。
地图比例碰撞 打印地图收藏的碰撞率的频率分布。
原始数组具有恒定值 列出了原始阵列,具有一个恒定值。
泄漏鉴定 组件举报顶端消费者 分析了可能的内存废弃物和其他低效组件。打印的最大对象。

它是不是在项目上下文菜单中可作为其中的一些较早已经描述查询的完整列表。有关可用查询更多信息,请参阅本文中的“延伸阅读”部分。

报告

内存分析工具有一个内置的报告系统,自动分析内存转储和生成报告的用户。报告的第一种类型是“泄漏疑点”的报告。MAT分析内存转储,并检查是否有可能维持生命的一些参考任何大的物体。请记住,这并不意味着泄漏嫌疑人实际上是真正的泄漏。第二个是“顶部组件”的报告 - 它包括对可能的内存浪费,最大的对象和有关引用的一些统计信息。这是一个伟大的地方去寻找内存优化。

泄漏疑点报告

该泄漏疑点报告包括有关潜在的泄漏问题的信息。重要的是要记住,这些列出的对象不必是实际的泄漏是非常重要的。它仍然是一个非常翔实的报告和一个伟大的地方开始寻找泄漏。该报告的主要组成部分是描述和最短路径,以聚点。第三个组成部分(由类累计对象),距离第二个(只是排序的类)派生。

图。 13

图。13

“最短路径为聚点”是一个非常有用的组件为开发人员可以立即检查什么可保持聚点被垃圾收集。
图。 14

图。14

顶部组件报告

这是一个非常翔实的报告,特别是对那些谁正在寻找一种方法来减少内存使用。它由内存废弃物嫌疑人和有关引用的一些数据。整份报告都是自我解释所以没有必要详细描述它。

图。 15

图。15

图。 16

图。16

使用MAT检测内存泄漏

本节将介绍在发生内存泄漏的实际使用内存分析工具。就本节而言用一备的内存泄漏一些示例代码是必要的。

与内存泄漏示例代码

此示例代码写入到显示内存泄漏的主要原因,并提供与MAT工作的材料。有两种最常见的内存泄漏类型。第一种是静态引用非静态内部类,这将保持一个参考的活动,并防止它被GC。当每一个屏幕方向变化的onCreate方法会被调用,一个新的MainActivity实例将被创建。由于旧的引用,旧的活动将不会被垃圾收集。第二种情况被称为“上下文泄漏”。这种情况下是很难发现传递给一个静态类,它保持它作为一个领域应用程序的上下文中的主要问题在于 - 这当然是一个硬引用。

第一个内存泄漏演示

这是第一个内存泄露的源代码,将让MainActivity被释放的GC。当然对象和类名被选择为使得它更容易表现出泄漏。在现实生活中的情况就不会那么容易。

公共类 MainActivity 延伸活动{
   非静态内部类的/ /静态字段-非常糟糕的主意!
  静态 MyLeakedClass leakInstance = NULL;

  @覆盖
  公共无效的onCreate(捆绑savedInstanceState){
     超级的onCreate(savedInstanceState);

    / /静态字段初始化
    ,如果(leakInstance == 
      leakInstance =  MyLeakedClass();

    ImageView的MVIEW =  ImageView的();
    imView.setBackgroundResource(R.drawable.leak_background);

    的setContentView(MVIEW);
  }

  / *
   *内部类,它不是一成不变的。
   * / 
   MyLeakedClass {
     整数 someInt;
  }
}

首先来看看从这段代码输出的LogCat中。连接的设备,运行logcat中,启动应用程序并旋转装置几次。下面是示例输出的LogCat中,如图17:

图。 17

图。17

第一次旋转后的差大约是3MB。再过旋转堆的大小由3MB再次增长。它是第一个警告的东西是不正确的。也LogCat中不显示释放分配的内存的任何迹象。现在是时候来看看什么是应用程序的内存里面怎么回事。运行DDMS工具,得到HPROF文件并打开它的内存分析工具里面。

主屏幕是有一些导致泄漏 - 它看起来应该与此类似图18所示:

图。 18

图。18

饼图显示,显著数额整个内存的保留资源 - 这是一个具有图形用户界面的任何应用程序的正常行为,但此示例代码里面只有一个资源,以便该问题可能躺在那里。还有两个FrameLayout中的实例(每个3MB)需要调查。有迹象表明,开发商可以按照来检测内存泄漏的几个路径。

基于直方图的搜索

让我们来看看直方图视图。还有就是内存的字节数和Bitmap类分配了显著金额。来看看一个Bitmap类对象的引用传入。这份名单应该是这样的,如图19所示:

图。 19

图。19

有三个大位图在内存中。该示例应用程序应该有最差的一个或两个内存泄漏。的内存量适合LogCat中输出。让我们来检查路径对GC根(不包括所有类型的弱引用)的每个实例。第一个位图对象,似乎它有一个引用本身,所以它不会被任何外部参考举行,并等待垃圾回收器来照顾它要被罚款。

图。 20

图。20

第二个有一点点更多的参考资料,但一切都显得平凡。看来,这个对象是一个积极的(可见的)位图 - 这就是为什么它引用了该活动,背景,窗口管理等。

图。 21

图。21

第三位是一个打击。它只有一个硬盘的参考路径,GC根,它是由“leakInstance”对象中。这表明,“leakInstance”对象,防止收集的位图。

图。 22

图。22

也有MainActivity的道路上 - 这并不奇怪,看着大家都知道,每一个屏幕旋转(这将创建一个新的Activity)有泄漏。让我们来看看发生了什么。首先使用正则表达式过滤器来查找直方图视图中MainActivity对象。

图。 23

图。23

第一个警告是,有MainActivity的三个实例。当然,这并不一定是一个漏,因为有时活动保持活力长于其他对象,但让我们来看看如果有什么会阻止他们得到的GC。要做到这一点,列出所有与传入的引用的对象。作为直方图显示有三个不同的实例。现在是时候检查路径到GC根。

图。 24

图。24

又是第一个MainActivity对象都有一个引用上下文,ActivityThread所以看起来它是目前活跃的活动。

图。 25

图。25

第二个对象再次拥有一个引用本身,所以它正等待被垃圾收集。一切都很好了这一点。

图。 26

图。26

现在第三个 - 这是一击!有一个硬引用leakInstance对象,它可以防止这种活动被横扫由GC。
图。 27

图。27

基于支配树搜索

有很多方法,开发人员可以找到内存泄漏。本文将仅显示其中的几个。第二个将基于一个支配树视图。打开HPROF转储的支配树视图。由保留堆大小排序的列表的内容。正如预测的那样在列表顶部的资源是那些具有最大保留的堆,但也存在的FrameLayout类(3MB每个)三个实例和一个Bitmap类的实例(1MB)。该FrameLayout中物体看起来很可疑,所以让我们来仔细看看它们。由于支配树已经显示出真正的对象,所以它是可以显示的路径,GC根不先列出参考文献。

图。 28

图。28

第一项实际上是一个打击!对GC根的唯一途径是通过“leakInstance”对象,这样有泄漏。

图。 29

图。29

第二个和第三个对象是当前帧版式视图中,一个正在等待得到收集。

图。 30

图。30

让我们来看看位图对象,因为它也可能导致泄漏。选择android.graphics.Bitmap并显示其路径GC根所不包括的所有弱引用。

图。 31

图。31

有位图类型的三个对象,以便为他们每个人寻找到GC根的路径。

这种情况重演 - 其中的两个实例都清楚(他们有引用到系统类),但第三个实例指向“leakInstance”,所以它是维持生命这个参考。

图。 32

图。32

大概有几百得到实际泄漏的方法。它是由开发人员来选择哪条路,他应该采取以及如何分析内存。

第二个内存泄漏演示

第二个内存泄漏的情况,包括应用程序上下文。它被作为参数传递到另一个单独的类,并在现场保存在那里。整个过程将继续MainActivity被收集的垃圾收集器。相同的结果可以通过保持上下文静态字段应该避免使这种做法来实现。为了避免重复,只有一个方法查找泄漏的方式进行说明。

这里是代码:

公共类 MainActivity2 延伸活动{
  SingletonClass mSingletonClass = NULL;

  @覆盖
  公共无效的onCreate(捆绑savedInstanceState){
     超级的onCreate(savedInstanceState);。
     mSingletonClass = SingletonClass.getInstance();
  }
}

 SingletonClass {
   私人上下文mContext = NULL; 
  私有静态 SingletonClass mInstance;

  私人 SingletonClass(上下文上下文){
     mContext =上下文;
  }

  公共静态 SingletonClass的getInstance(上下文上下文){
     如果mInstance == ){
       mInstance =  SingletonClass(上下文);
    }
    返回  mInstance;
  }
}

运行应用程序,倾倒HPROF文件和MAT运行它之后与此类似的一个概览屏幕上将会出现。

图。 33

图。33

概览屏幕并没有告诉任何重要的,所以开发人员必须继续他的搜索。在这个片段中有没有位图或许多资源,但直方图视图显示,有MainActivity的许多实例 - 检查他们可能会提供一些​​进一步的信息。

图。 34

图。34

该装置旋转3次,直方图显示,有MainActivity的四个实例。现在是时候检查是否有从垃圾收集使他们的任何对象。要做到这一点,列出与传入的引用的对象。只是通过扩展一审认为有一个暗示,这个对象是当前活动(它包含对ActivityThread)。

图。 35

图。35

继续搜索,并列出路径GC根有一些包含对自己和一个实例指向mInstance内SingletonClass和参考到目前的活动(从mSingletonClass)的两个实例。即泄漏。

图。 36

图。36

它是清晰可见的垃圾收集,防止由上下文。还有另外一个问题 - 创造活动的另一个实例后传递给SingletonClass的背景下保持不变。这是一个关键问题。上下文引用指向一个活动,不再是必要的,但保持正因为如此活着。这样的问题可能是应用非常关键的,可以创建不必要的行为,而且很难被发现在更大的项目。

补充阅读

内存分析是一个广泛的话题,不能在很短的文章呈现的细节。有专门用于内存管理的许多书籍,文章和演讲。下面是一个简短的清单,读者可以用它来进一步陷入这个话题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MAT工具使用说明.docx MAT(Memory Analyzer Tool)工具入门 一MAT简介 MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。 二 使用MAT意义 当服务器应用占用了过多内存的时候,会遇到OutOfMemoryError。如何快速定位问题呢?Eclipse MAT的出现使这个问题变得非常简单。它能够离线分析dump的文件数据。 四 MAT操作流程 1先调用jdk的工具得到heap使用情况 我安装的是jdk1.6 C:/>java -version java version "1.6.0_11" Java(TM) SE Runtime Environment (build 1.6.0_11-b03) Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing) 2调用jdk工具jps查看当前的java进程 C:/>jps 3504 Jps 3676 Bootstrap 3496 org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar 3调用jmap工具得到信息 C:/>jmap -dump:format=b,file=heap.bin 3676 Dumping heap to C:/heap.bin ... Heap dump file created 这时,我们的C盘根目录,就生成了heap.bin文件。 4用eclipse的file---->open打开这个文件,首先是一个启动图: 这里可以选择查看 (1)内存泄露报表,自动检查可能存在内存泄露的对象,通过报表展示存活的对象以及为什么他们没有被垃圾收集; (2)对象报表,对可颖对象的分析,如字符串是否定义重了,空的collection、finalizer以及弱引用等。 我这里选择的是查看内存报表,以下是截的简略图: 通过报表展示,蛮清楚的,下面还有详细的说明,这里就没有帖图了,有兴趣的可以继续探究。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值