浅谈JVM虚拟机运行时数据区运行原理

深入理解JVM运行时数据区 运行时数据区可简单分为Native Method Stack(本地方法栈)、Program Counter Register(程序计数器)、Java Virtual Machine Stack(虚拟机栈)、Heap(堆区)和Method Area(方法区)。在Java中存在一个类Runtime,该类采用了单例设计模式,每一个Java应用程序都有当前类Runtime的唯一实例。 阅读详情

目录

一,前言:

二,程序计数器(Program Counter Register)

 三,虚拟机栈

 (一),局部变量表(LVT)

1.1概念

1.2LVT(局部变量表)具有的特点:

 1.3 解析局部变量表

 (二)操作数栈(OS)

2.1操作数栈的概念

2.2 解析操作数栈工作原理

(三)动态链接(Dynamic Linking):

3.1概念

 四,本地方法栈(Native Method Stack)

五,方法区(Method Area)

 六,堆区

(一)堆的概念

(二)堆的分代管理

 (三)有关堆的垃圾回收机制(GC)


一,前言:

JVM(Java Virtual Machine) 即java虚拟机,主要由字节码指令集、寄存器、栈、垃圾回收堆和存储方法域等构成。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码

(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行

我们都知道,java源文件通过编译器编译后能形成对应的class文件,即字节码文件,那什么是字节码文件呢?------->>也就是由Java编译器用javac命令编译、运行在JVM上的一种8位二进制字节流,这些字节流数据里包含了java类所有的相关信息,如常量池,接口,父类,子类信息等,而字节码文件再通过java虚拟机的解释,就将字节码编译成特定机器上的机器码。

Java程序运行的过程中,JVM会将其所管理的内存划分成若干个区域,统称为是运行时数据区。其中,一些线程间共享的区域,随着JVM的启动而创建,JVM的退出而销毁;另一些线程私有的区域,则随着线程的开始而创建,线程的结束而销毁。如图所示,运行时数据区由以下几个区域所组成:程序计数器、Java虚拟机栈、本地方法栈、方法区、堆。


先上一张图简单说明下JVM的内存模型:

(Ps:此图来源于网络 侵删)

注:堆和方法区是所有线程共有的,而虚拟机栈,本地方法栈和程序计数器则是线程私有的。


二,程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,可以忽略不计,通俗地讲:就是在线程中指示字节码应当执行的位置 或者说在当前线程中执行字节码的行号指示器,JVM工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,另外,因为CPU需要不断的切换各个线程,这样来回切换以后 ,需要有计数器来保存各线程最初执行的位置,切换回来后便知道从哪开始执行。这也是为什么每条线程都有一个独立的程序计数器的原因。所以,我们称这类区域为“线程私有”的内存。

下面 我们在idea上用jclasslib插件 将class文件反编译成我们能看懂的文件来帮助我们理解程序计数器   如图:

 三,虚拟机栈

与程序计数器一样,java虚拟机栈也是线程私有的,它的生命周期与线程相同,描述的是Java方法执行的内存模型:每执行一个方法时,都会同时创建一个栈帧(Stack Frame)用来存储局部变量表,操作数栈,动态链接,方法出口等信息。同时,方法调用结束也对应着相关栈帧的出栈,释放在栈中的空间,空间结构如图所示:

 (一),局部变量表(LVT)

1.1概念

是一个索引以0开始的字节数组,存储了一个方法的所有形参和局部变量。LVT所存储的类型都是编译期间可知的,包括各基础的数据类型(byte,short char float double等),对象引用(reference类型)

1.2LVT(局部变量表)具有的特点:

<1>第0个槽位(Slot)固定存储指向方法对象的this指针(注: 变量槽是Lvt最基本的存储单元)

<2>除了long和double 占用两个连续的Slot外,其他的类型只占用一个Slot

<3>局部变量表按照变量的声明顺序来进行存储

通过如下代码进行验证:

 class  Lvt{
    public int showLvt(byte b,char c, int i, long l){
        float f=0;
        double d=0;
        Object ref=new Object();
        int ret=i;
        return ret;
    }
}
编译源文件后 在terminal终端 用javap -verbose Lvt.class    #解析.class文件   

 1.3 解析局部变量表

在解析出的class文件中 我们可以看到 局部变量表(LocalVariableTable) 所展示的信息:如下

 

 通过上图的结果,我们可以分析变量名所对应的签名(Signature)和Slot(槽位)  如第0个Slot的名字为this指针 ,其签名为 L作业/Lvt 表示是指向Lvt类型对象的this指针

 (二)操作数栈(OS)

2.1操作数栈的概念

用于存储方法运算过程中所产生的结果或赋予局部变量的值,它是一个后入先出栈(LIFO)。同局部变量表一样,操作数栈的最大深度也在编译的时候写入到方法的Code属性的max_stacks数据项中

2.2 解析操作数栈工作原理

JVM提供了对OS的出栈和入栈的命令,如load表示入栈指令,store表示出栈指令,下面编写一段代码帮助大家理解

    public int showOs(int a, int b) {
        int c = a + b;
        return c;
    }

 编译源文件后 在terminal终端 用javap -verbose Lvt.class    #解析.class文件   

在解析的文件中找到对应的函数处(showOs()  ) 如图所示

对以上解析文件进行解读:iload_1: 将局部变量表中Slot索引为1的变量a对应的值送入操作数栈,iload_2: Slot索引为2的变量b也送入操作数栈中;iadd:表示将两个数出栈相加后结果入栈,istore_3: 表示将得到的结果送入到局部变量表 变量c的位置处  iload_3:表示将索引为3的c对应的值入栈(OS)  ;最后ireturn:表示方法的返回,结束操作

 OS工作的原理图(对应解析文件):

 (Ps 此图来源于网络 侵删)

(三)动态链接(Dynamic Linking):

3.1概念

在一个class文件中,一个方法要调用其他方法,需要将这些方法的符号引用转化为其在内存地址中的直接引用,而符号引用存在于方法区中的运行时常量池。

Java虚拟机栈中,每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,持有这个引用的目的是为了支持方法调用过程中的动态连接(Dynamic Linking)。

这些符号引用一部分会在类加载阶段或者第一次使用时就直接转化为直接引用,这类转化称为静态解析。另一部分将在每次运行期间转化为直接引用,这类转化称为动态连接。

class  Cpr{
   private int a=0;
   public void cpr1(){}
   public void cpr2(){
   int b=a;
   cpr1();
    }
}

编写如上的代码 ,采用与操作数栈同样的方法对class源文件进行解析,如下图所示:

 

 从中我们可以发现cpr2()函数的指令码中 使用到了两处符号引用#7 #13 ,对应的在常量池查找对应的符号 :

 即#7代表的是字段的符号引用 #13代表的是方法的符号引用  最终分别解析成指向整型变量a,指向无返回值的cpr1()函数

 四,本地方法栈(Native Method Stack)

本地方法栈 的作用与Java虚拟机栈类似,区别在于后者是为Java方法服务,而本地方法栈则为native方法服务。Java虚拟机规范没有对native方法机制及其实现语言做强制规定,如果JVM不提供native方法,则无需实现本地方法栈。

本地方法栈既可以被实现成固定大小,也可以实现成可动态地扩展和收缩,因此在特定的场景下也会抛出StackOverflowError异常和OutOfMemoryError异常。

五,方法区(Method Area)

方法区,与Java堆一样是各个线程共享的内存区域。用于存储被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范将方法区描述为堆的一个逻辑部分,但是它却有个别名叫做Non-Heap(非堆),目的就是和Java堆区分开来。运行时常量池也是存放于方法区中。

在Java8中,HotSpot虚拟机改变了原有方法区的物理实现,将原本由JVM管理内存的方法区的内存移到了虚拟机以外的计算机本地内存,并将其称为元空间(Metaspace)

 下面用一张表来说明方法区中的存储的类的哪些信息

1、类型信息

类的完整名称

类的直接父类的完整名称

类的直接实现接口的有序列表

类型标志(类类型还是接口类型)

类的修饰符(public private defautlabstract final static)

2、类型的常量池存放该类型所用到的常量的有序集合,包括直接常量(字符串、整数、浮点数)和对其他类型、字段、方法的符号引用。
3、字段信息(该类声明的所有字段)

字段修饰符(public、peotect、private、default)

字段的类型

字段名称

4、方法信息

方法信息中包含类的所有方法。

方法修饰符

方法返回类型

方法名

方法参数个数、类型、顺序等

方法字节码

操作数栈和该方法在栈帧中的局部变量区大小

异常表

5、类变量(静态变量)
6、指向类加载器的引用
 7、指向Class实例的引用
8、方法表
9、运行时常量池(Runtime Constant Pool)

 六,堆区

(一)堆的概念

堆(Heap)是运行时数据区中最大的一块区域,绝大部分的对象(包括类实例和数组)都在上面存储。堆是所有线程共享的,随着JVM的启动而创建。我们通过new创建出来的对象都分配于此,而且无需主动释放对象内存,统一由垃圾收集器(Garbage Collector,GC)来进行管理和销毁 —— 这也是Java跟C++相比区别最大的特点之一。当堆中没有足够的内存来创建对象时,就会抛出OutOfMemoryError异常

(二)堆的分代管理

从上图分析 ,堆被分为年轻代、老年代两个区域,年轻代还被进一步划分为 Eden 区、From Survivor 0、To Survivor 1 区。并且默认的虚拟机配置比例是Eden:from :to = 8:1:1 。

Java堆 = 老年代 + 新生代

新生代 = Eden + S0 + S1
 
默认Eden:from :to = 8:1:1

 (三)有关堆的垃圾回收机制(GC)

Eden区(存放新生对象),两个幸存区(From Survivor和To Survivor)(存放每次垃圾回收后存活的对象) 

大多数情况下,对象在新生代 Eden 区中分配。当 Eden 区没有足够空间分配时,虚拟机将发起一次 Minor GC。  对在Eden区的无效的对象(即堆中的对象没有被栈中的变量引用时)进行回收;将仍存活的对象移到From Survivor区 ,此时Eden区空间清零。

经过 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1,对象在 Survivor区中每熬过一次 Minor GC,年龄就增加 1,当它的年龄增加到一定程度(并发的垃圾回收器默认为 15),CMS 是 6 时,就会被晋升到老年代中。

Ps:初学Java,有什么问题的地方,还希望大佬们给我指正下!

ESP32-S3射频测试与全球认证全栈实践指南 功率谱密度(PSD)和发射功率等级是无线通信设备射频合规的核心基础概念,其物理层原理直接决定自适应测试、阻塞容限及多国认证的通过路径。PSD ≥10 dBm/MHz触发强制性自适应测试,需验证LBT机制与跳频鲁棒性;而16级可编程发射功率等级(-24 dBm至+20 dBm)则为功耗、覆盖与法规平衡提供工程调控维度。该能力广泛应用于低功耗蓝牙IoT终端、智能家居网关及工业无线传感器等场景,尤其在ESP32-S3平台中,需结合eFuse校准、Sigma工具链与QuickTrack认证策略实现从实验室调试到量产 阅读详情

相关推荐

从零开始的机械臂yolov5抓取gazebo仿真(一)

本文介绍了如何将机械臂模型导出为URDF

qq_48427527的博客 1万+

虚拟机基础04---jvm管理的内存(运行时数据区)

复习回顾专用

m0_73722544的博客 465

Arduino安装图文教程:小白也能轻松上手

手把手带你完成Arduino安装全过程,无论你是编程新手还是硬件小白,都能快速搭建开发环境。结合arduino安装教程与实操步骤,避开常见错误,让创作即刻启程。

weixin_35509395的博客 1107

java 实现自动派单(自动分配任务)

需求: 最近要实现一个自动派单功能,就是如果有任务来了,那么任务平均分配给现有的员工,如果之前取了任务的员工下次来任务时就分配给下一个,如果有新员工则将员工添加到队列的最后,如果有员工离职就将员工信息从队列里移除。   实现: 1.写一个定时任务,定时将任务放入任务队列中TaskQueue,并将员工放入User队列中,如果员工已存在则不添加,如果新员工则加入队列中,如果员工不存在了就从...

yiding123的专栏 1万+

Surface Pro 4/5/6/7保姆级黑苹果安装:从Windows分区到OC引导配置全流程(含EFI文件替换避坑)

本文详细介绍了在Surface Pro 4/5/6/7上安装黑苹果的全流程,包括Windows分区、OC引导配置和EFI文件替换等关键步骤。通过实战经验分享,帮助用户避开常见陷阱,实现Windows与macOS双系统完美共存,特别适合对黑苹果安装感兴趣的Surface Pro用户。

weixin_30300225的博客 1373

数字IC设计之时序分析基础概念汇总

时序分析主要有两种办法:静态时序分析: (static timing analysis,STA),是遍历电路存在的所有时序路径,根据给定工作条件(PVT)下的时序库.lib文件计算信号在这些路径上的传播延时,检查信号的建立和保持时间是否满足约束要求,根据最大路径延时和最小路径延时找出违背时序约束的错误。

weixin_45230720的博客 5607

JVM运行时数据区域详解

根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域:对于不同的虚拟机实现,在运行时数据区的实现上并不完全相同。对于常用的HotSpot虚拟机来说,它的运行时数据区如下:主要区别在于,HotSpot使用了直接使用本地内存(即机器本身内存)的(metaspace)来实现方法区。下面针对每个具体的数据区域进行详细的介绍。程序计数器()是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。JVM可以同时支持多个执行线程。

Huangjiazhen711的博客 863

2026年摩尔线程数字IC面试试卷带答案

本文摘要: 该试卷为数字IC设计笔试,满分120分,时长90分钟,包含单选题、波形分析题、多选题和代码设计题。重点考察时序约束(如set_false_path)、建立/保持时间、逻辑化简、复位机制、AXI协议、半导体工艺、状态机、GPU架构等核心知识点。多选题涉及异步FIFO设计、Verilog综合、亚稳态处理、C++关键字和低功耗技术。代码题要求实现单比特信号去毛刺电路,需稳定4个时钟周期才输出。试题解析详细,标注了企业面试高频考点,如摩尔线程自研的MUSA架构和花港GPU架构特点。整体内容专业性强,覆盖

Open 98

【预警】有点干,JVM运行时数据区(计数器、虚拟机栈、本地方法栈、堆、方法区)

大家好,,这篇文章咱们聊下JVM性能优化的问题 这篇文章主要介绍下JVM的运行数据区相关的内容,包括: 程序计数器 虚拟机栈 本地方法栈 堆 方法区 案例 和总结 好了,开始干货环节~ 作为一个常识性的知识,大家都知道字节码只是一个二进制文件存放在那里。要想在jvm里跑起来,先得有个运行的内存环境。 也就是我们所说的jvm运行时数据区。 1)运行时数据区的位置 运行时数据区是jvm中最为重要的部分,执行引擎频繁操作的就是它。类的初始化,以及后面我们讲的对象空间的分配、垃圾的回收都是在这块区域发生的。 )

博学谷狂野架构师的博客 887

基于ArduPilot的旋翼式无人机飞行器开发系列(二,学习路线)

一,热爱 作为一名耿直的技术男,在这里我只想说一句,热爱是可持续学习的第一要素,也只有热爱才能让你坚持到最后。 至于最后能得到什么,只有你自己知道。常说书中自有颜如玉,书中自有黄金屋。如果你是为了颜如玉,我相信大多数颜如玉做不了你的红颜知己。如果是为了黄金屋,当你持续投入时间和金钱却看不到回报的时候,相信退堂鼓早已隆隆作响。 我给自己的信条就是为当下努力工作,为将来持续学习。当前飞控行业并没有爆发,如果想赚块钱,去互联网汽车,去VR/AR吧,去元宇宙吧。 那么我热爱...

从0到1,突破自己 1670

LLCC68芯片系统架构与LoRa驱动开发核心解析

LoRa射频收发器是低功耗广域物联网(LPWAN)的关键组件,其本质是集成了调制解调器、协议引擎、数据缓冲区与电源管理的专用SoC。理解其工作模式状态机(Sleep/Standby/TX/RX)与SPI主机接口时序规范,是实现稳定通信的基础。LLCC68通过寄存器映射与命令集双接口抽象硬件控制,支持LoRa扩频调制与FSK兼容模式,具备高链路预算(157 dB)和DC-DC/LDO动态电源切换能力。典型应用场景包括远距离传感器节点、智能表计与工业无线监测系统。本文深入剖析LLCC68的信号链路径、中断机制与

weixin_29859471的博客 283

虚拟机系列 | JVM运行时数据区

1、内存结构 内存是计算机的重要部件之一,它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。JVM的内存结构规定Java程序在执行时内存的申请、划分、使用、回收的管理策略,通说来说JVM的内存管理指运行时数据区这一大块的管理。 2、线程运行 JVM中一个应用是可以有多个线程并行执行,线程被一对一映射为服务所在操作系统线程,调度在可用的CPU上执行,启动时会创建一个操作系统线程;当该线程终止时,这个操作系统线程也会被回收。 ...

JavaJIAMIN的博客 655

自适应控制 (Adaptive Control) 算法详解及案例分析

自适应控制是一种能够在线调整控制器参数以适应系统动态变化的控制方法。其核心思想是通过实时估计系统参数或调整控制器参数,使系统在不确定性或动态变化的环境中仍能保持稳定性和性能。

闲人编程的博客 4085

JVM如何运行,揭秘Java虚拟机运行时数据区

介绍Java虚拟机运行时数据区的结构。在运行时数据区中,总的来说分为五个部分。程序计数器,本地方法栈和虚拟机栈是线程私有的,方法区和堆内存是线程共享的。

m0_62946761的博客 3733

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

JVM运行时数据区(详解+面试)

1.概述 JVM的运行时数据区,不同虚拟机实现可能略微不同,但都会遵从Java虚拟机规范,Java 8虚拟机规范规定,Java虚拟机所管理的内存将会包括一下几个运行时数据区域: 程序计数器(Program Counter Register) 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。 java中最小的执行单位是线程,因为虚拟机的是多线程的,每个线程是抢夺cpu时间片,程序计数器就是存储这些指令去做什么,比如循环,跳转,异常处理等等需要依赖它。 每个线程都有属于自己.

qdzjo的博客 6120

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

必知必会JVM二-运行时数据区

1、什么是运行时数据区 恩......如果我说什么是Java的内存模型,估计大家都会脱口而出,程序计数器、方法栈、本地方法栈、元空间、堆。而且很自信的觉得自己说的一点都没错。areyoureally? 其实对于java的内存模型和运行时数据区都搞不清楚。java的内存模型是JMM(Java Memory Model,简称 JMM )是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式,如果我们要想深入了解Java并发编程,就要先理解好Java内存模型..

b379685397的博客 2万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

面试必问的 JVM 运行时数据区,你懂了吗?

面试必问的 JVM

程序员囧辉 8199

《Java虚拟机原理图解》3、JVM运行时数据区

JVM运行时数据区(JVM Runtime Area) 其实就是指JVM在运行期间,其对计算机内存空间的划分和分配。本文将通过以下几个话题来讨论JVM运行时数据区。 Topic 1. JVM运行时数据区 里有什么?Topic 2. 虚拟机栈 是什么?虚拟机栈 里有什么?Topic 3. 栈帧是什么?栈帧 里有什么?Topic 4. 方法区 是什么?方法区 里有什么?

我的程序人生(亦山札记) 2万+

JVM调优:JVM运行时数据区详解

JVM调优:JVM运行时数据区详解。

永远保持随时离开的技术能力! 1762

Java 运行时数据区详解

本文主要介绍了Java运行时数据区相关内容,包括程序计数器、Java虚拟机栈、本地方法栈、堆、方法区等内容。

专注Java和MySQL领域知识分享 1991

JVM运行时数据区——运行时数据区及线程概述

JVM通常会根据运行环境和代码的特性动态地选择解释模式或编译模式。在程序启动时,JVM会使用解释模式来快速启动,然后根据代码的热点(HotSpot)来判断是否进行即时编译

胡晗靓的Java学习博客 702

JVM运行时数据区结构及原理

下图红色区域(即堆和方法区):一个进程对应一份,一个进程可以有多个线程,即是线程共享的。JVM允许一个应用有多个线程并行执行 灰色区域(即PC、栈、本地栈):每个线程都拥有一份,即是线程独立的。 每个JVM只有一个Runtime实例(即运行时数据区)。 ...

S mile0804的博客 1815

JVM规范之运行时数据区域

本文基于JVM8规范,介绍了JVM运行时数据区的组成及其功能。JVM运行时数据区分为线程私有和线程共享两类。线程私有的数据区包括程序计数器(PC Register)、Java虚拟机栈(JVM Stack)和本地方法栈(Native Method Stack);线程共享的数据区包括堆(Heap)、方法区(Method Area)和运行时常量池(Run-time Constant Pool)。

Erictr的博客 1304

【JVM原理】运行时数据区(内存结构)

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。

m0_66584716的博客 1476

JVM 运行时数据区

JVM 的运行时数据区是 Java 程序执行时的核心组件,它管理着程序的内存分配、方法调用、线程执行等各个方面。理解 JVM 运行时数据区的结构和工作原理对于优化 Java 程序的性能、解决内存问题至关重要。在开发和调试过程中,合理配置 JVM 参数、监控内存使用情况,并及时发现和解决内存问题,是保障 Java 应用稳定运行的重要环节。

Flying_Fish_roe的博客 1210

JVM从零到一系列:03--运行时数据区【PC寄存器,虚拟机栈】

0x01.运行时数据区概述 1.运行时数据区模型图(整体图) 2.运行时数据区模型图(详情图) 3.概述 Java虚拟机定义了若干程序运行期间会使用到的运行时数据区: 有一些会随着虚拟机的启动而创建,随着虚拟机退出而销毁。 还有一些与线程一一对应,与线程对应的数据区会随着线程的开始和结束而创建和销毁。 独立的线程:【程序计数器,栈,本地栈】 共享的线程:【堆,堆外内存,方法区】 Java虚拟机与线程: 线程是一个程序运行的单元,JVM允许一个应用有多个线程。 HotSpot中,每个线程都与

ATFWUS的博客 3万+
上一篇: 二叉树的基本操作(代码+注释)
下一篇: 刨析Java中浅拷贝和深拷贝
Pursuit@H
博客等级 码龄6年 76粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pursuit@H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值