“深入探索JVM内部机制:解密Java虚拟机的奥秘“

【嵌入式】树莓派部署NCNN的YOLOv5模型 树莓派部署NCNN框架的YOLOv5模型 阅读详情

标题:深入探索JVM内部机制:解密Java虚拟机的奥秘

摘要:本文将深入探索Java虚拟机(JVM)的内部机制,介绍JVM的基本原理、运行时数据区域以及垃圾回收机制,并通过示例代码解释这些概念。

正文:

一、JVM的基本原理

Java虚拟机(JVM)是Java语言的核心,它是一个在操作系统上运行的虚拟计算机。它的主要任务是执行Java字节码,并提供运行时环境,包括内存管理、垃圾回收和线程管理等。

JVM的基本原理是将Java源代码编译成字节码,然后由JVM解释执行或者即时编译成本地机器码。在解释执行的方式下,JVM逐条解释字节码指令并执行;而在即时编译的方式下,JVM会将频繁执行的字节码翻译成本地机器码,以提高执行效率。

二、运行时数据区域

JVM的运行时数据区域分为线程私有区域和线程共享区域。

  1. 线程私有区域:

    • 程序计数器(Program Counter,PC):用于指示当前线程执行的字节码指令的地址。
    • Java虚拟机栈(Java Virtual Machine Stack):用于存储方法调用和局部变量等信息。
    • 本地方法栈(Native Method Stack):用于支持本地方法的执行。
  2. 线程共享区域:

    • 堆(Heap):用于存储对象实例。
    • 方法区(Method Area):用于存储类信息、常量、静态变量和即时编译器编译后的代码等。
    • 运行时常量池(Runtime Constant Pool):用于存储编译期生成的字面量和符号引用。

三、垃圾回收机制

JVM通过垃圾回收机制自动管理内存,释放不再使用的对象。

  1. 引用计数法(Reference Counting):通过给对象添加引用计数器,当引用计数为0时,表示对象不再被使用,可以回收。
    但该方法无法解决循环引用的问题。

  2. 标记-清除法(Mark-Sweep):通过标记阶段标记出所有可达对象,然后清除阶段回收未被标记的对象。
    但该方法容易产生内存碎片。

  3. 复制算法(Copying):将堆分为两个相等大小的区域,每次只使用其中一块,当这一块中的对象不再被引用时,将存活的对象复制到另一块中,然后清除当前块。
    该方法解决了内存碎片的问题,但浪费了一半的内存空间。

示例代码:

public class GarbageCollectionExample {
    public static void main(String[] args) {
        // 创建对象
        GarbageObject obj1 = new GarbageObject();
        GarbageObject obj2 = new GarbageObject();
        
        // 将obj2设置为obj1的成员变量
        obj1.setChild(obj2);
        obj2.setParent(obj1);
        
        // 将obj1和obj2设置为null,使其不再被引用
        obj1 = null;
        obj2 = null;
        
        // 手动触发垃圾回收
        System.gc();
    }
}

class GarbageObject {
    private GarbageObject parent;
    private GarbageObject child;
    
    public void setParent(GarbageObject parent) {
        this.parent = parent;
    }
    
    public void setChild(GarbageObject child) {
        this.child = child;
    }
}

在上述示例代码中,我们创建了两个对象obj1和obj2,并将它们互相引用。在将obj1和obj2设置为null后,我们手动触发垃圾回收,JVM会自动回收不再被引用的对象。

结论:

通过深入探索JVM的内部机制,我们了解了JVM的基本原理、运行时数据区域和垃圾回收机制。这些知识对于理解Java程序的运行原理、优化代码以及解决内存相关的问题非常重要。通过合理地利用JVM的特性,我们可以编写出高效、可靠的Java应用程序。

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

相关推荐

用LTspice仿真Buck电路输出电容:从参数计算到波形优化的全流程演示

本文详细介绍了使用LTspice仿真Buck电路输出电容的全流程,从理论计算到波形优化。通过解析关键参数如纹波电压、瞬态响应和ESR,结合工程计算方法和LTspice仿真技巧,帮助工程师优化Buck电路设计,解决输出纹波过大和瞬态响应不佳的问题。

night的博客 851

“深入探索JVM内部机制:解密Java虚拟机“

通过深入探索JVM的内部机制,我们了解了类加载过程、内存管理、垃圾回收机制以及JVM的调优与监控方法。熟悉JVM的工作原理对于开发人员优化和调试Java应用程序非常重要,可以帮助我们充分发挥Java语言的优势,提升应用程序的性能和稳定性。JVM提供了内存管理、垃圾回收、线程管理等功能,使得Java程序可以在不同平台上运行。摘要:本文将深入剖析Java虚拟机(JVM)的内部机制,探讨其工作原理以及与Java程序交互的过程。JVM通过运行时数据区域管理内存,包括方法区、堆、栈和本地方法栈等。

coder_jh的博客 659

ArcGIS实战:利用IDW反距离权重法实现气象数据的批量空间插值

本文详细介绍了如何利用ArcGIS中的IDW反距离权重法实现气象数据的批量空间插值。通过实战案例和脚本示例,展示了IDW插值在气象数据分析中的高效应用,包括算法原理、参数调优、批处理自动化及常见问题解决方案,帮助用户快速生成连续分布的气象地图。

weixin_29051149的博客 240

“深入探索JVM内部机制:解密Java虚拟机原理“

了解类加载、内存管理、垃圾回收、即时编译和运行时数据区域等关键概念,对于开发高性能的Java应用程序至关重要。摘要:本文将深入探索Java虚拟机(JVM)的内部机制,揭示其工作原理和关键组成部分,包括类加载、内存管理、垃圾回收、即时编译和运行时数据区域等。通过详细讲解JVM的原理和示例代码,帮助读者更好地理解JVM的内部机制,并能够优化Java应用程序的性能。JVM的垃圾回收是自动进行的,通过标记-清除、复制、标记-整理等算法来回收无用的对象。栈是线程私有的,用于存储局部变量和方法调用的状态。

coder_jh的博客 676

PythonWeb开发框架—Django之工程创建和models的定义和增删改查

文章介绍了Django工程的创建、models的定义和增删改查

weixin_42476668的博客 990

用Seurat和ComplexHeatmap绘制单细胞marker基因热图:从数据处理到可视化全流程

本文详细介绍了使用Seurat和ComplexHeatmap绘制单细胞marker基因热图的全流程,涵盖从数据处理、基因筛选、平均表达矩阵计算到高级可视化与注释添加。重点解析了如何利用ComplexHeatmap生成发表级热图,并整合热词信息,解决单细胞数据可视化中的常见问题,提升科研图表质量。

weixin_29048775的博客 529

“深入探索JVM内部机制:解密Java虚拟机的工作原理“

我们介绍了JVM的基本组成部分、类加载过程、内存管理和垃圾回收、即时编译器等关键概念,并通过示例代码帮助读者更好地理解JVM的工作原理。我们将介绍JVM的基本组成部分、类加载过程、内存管理和垃圾回收、即时编译器等关键概念,并通过示例代码帮助读者更好地理解JVM的工作原理。类加载器按照一定的规则和顺序查找并加载类文件,然后将类的字节码转换为可执行代码。类加载器负责将类文件加载到JVM中,并进行验证、准备、解析和初始化。Java虚拟机由三个主要的组成部分组成:类加载器、运行时数据区和执行引擎。

coder_jh的博客 729

Linux中断子系统(二)—— 通用框架处理

1、数据结构分析 (1)中断描述符结构structirq_desc: 1)打开CONFIG_SPARSE_IRQ宏(中断编号不连续),中断描述符以radix- tree来组织,用户在初始化时进行动态分配,然后再插入radix-tree中; 2)关闭CONFIG_SPARSE_IRQ宏(中断编号连续),中断描述符以数组的 形式组织,并且已经分配好; 3)不管哪种形式,最终都可以通过linuxirq号来找到对应的中断描述符; (2)stru...

weixin_38428439的博客 4871

“深入探索JVM:解密Java虚拟机的工作原理“

JVM通过跟踪对象的引用关系,确定哪些对象是可达的,哪些对象是不可达的,并将不可达的对象进行回收。本文深入探索了JVM的工作原理,包括字节码的执行过程、内存管理与垃圾回收、即时编译与优化等方面。摘要:本文将深入探索Java虚拟机(JVM)的工作原理,从字节码到实际执行过程,从内存管理到垃圾回收等方面进行解析,帮助读者更好地理解和优化Java程序的性能。Java虚拟机(JVM)是Java语言的核心,它负责将Java源代码编译成可执行的字节码,并在运行时进行解释执行。二、字节码的执行过程。

coder_jh的博客 1226

使用RustDesk或者AnyDesk的TCP隧道实现Codesys系列PLC的远程调试和下载

Codesys远程调试

exat500g的博客 7272

BevFusion (1): 传感器介绍

激光雷达,也称光学雷达(LIght Detection And Ranging)是激光探测与测距系统的简称,它通过测定传感器发射器与目标物体之间的传播距离,分析目标物体表面的反射能量大小、反射波谱的幅度、频率和相位等信息,从而呈现出目标物精确的三维结构信息。激光雷达是自动驾驶车辆的关键传感器,如下图所示,车辆上方旋转的圆柱体对应就是激光雷达传感器。

@bangbang的博客 1475

解密Java源码运行过程:从编写代码到JVM执行的奥秘

编译期:由JDK的javac工具将源代码(.java)编译成字节码(.class加载期:由JVM的类加载器(ClassLoader)将字节码加载到内存。运行期:由JVM的执行引擎解释或编译执行内存中的字节码。整个过程的核心在于JVM(Java虚拟机),正是它构筑了“一次编写,到处运行”的跨平台基石。(示意图:Java从源码到执行的全过程)回顾整个旅程,Java从源码到执行的奥秘,本质上源于出色的抽象和隔离。字节码抽象了硬件:它将程序员从具体的平台指令中解放出来。JVM隔离了操作系统。

xm123m的博客 853

【大数据技术干货】(还不懂数仓,数据中心?看这一篇就够了!)在实际的开发生产中,让你了解企业级数据中心整体架构(DB+ETL+ODS+DW+DM)的各个层次的过程详解,数据联系及功能区分

一 企业级数据中心架构 数据仓库的整体架构,各个系统的元数据通过ETL同步到操作性数据仓库ODS中,对ODS数据进行面向主题域建模形成DW(数据仓库),DM是针对某一个业务领域建立模型,具体用户(决策层)查看DM生成的报表。 二 DB 三 ETL(Extract-Transform-Load) ETL是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程,目的是将企业中的分散、零乱、标准不统一的数据整合到一起,为企业的决策提供分析依据。 ETL是BI项目重要的一个环节。 通常情况下,在BI项目中ET

liuchunhang的博客 1289

解密Java虚拟机深入探索JVM内存管理与垃圾回收机制

好的,我将按照您的要求,撰写一篇关于解密Java虚拟机深入探索JVM内存管理与垃圾回收机制的文章。

jisumuma的博客 438

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

解密 `java.lang.ClassNotFoundException`:从JVM类加载机制到实战排错(Java小白必读)

`java.lang.ClassNotFoundException` 是Java开发中一个非常常见的运行时异常。当Java虚拟机(JVM)在运行时尝试通过类名动态加载一个类(例如使用 `Class.forName()` 或通过类加载器显式加载),但在其类搜索路径(Classpath)下找不到对应的 `.class` 文件时,便会抛出此异常。这通常与类路径配置错误、依赖的JAR包缺失、打包问题或类名书写错误等因素紧密相关。本文将以“小白”视角出发,从`ClassNotFoundException`的表象入手,

沉淀所学,分享所思,让热爱与成长同行。商务记录AI实战经验,助力开发者快速成长。 热爱AI,希望做出有影响力的技术成果。 技术点亮生活,分享连接价值与机会。 专注AI落地实战,陪你走好技术每一步。 2739

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

《Java源码解密从JVM到分布式架构的深度探索》

通过解析`ClassLoader`源码,可发现其`findClass`方法与`defineClass`方法间复杂的作用关联,揭开双亲委派机制的实现逻辑。通过解析Istio项目中的`envoy`控制逻辑,可理解Java代理类生成的底层过程:`Proxy.newProxyInstance`方法如何将InvocationHandler的invoke方法编译成本地字节码,以及CGLIB在实现无接口代理时的`$EnhancerByCGLIB`类构造机制。利用OSGi的`Bundle`模型实现细粒度的类空间划分。

qHlfvLVx的博客 868

假人有限元模型

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

JVM初始化:核心机制与性能调优

开发者可以通过继承。

AIHacksCash的博客 833

深入探索编译插桩技术(三、解密 JVM 字节码)

JVM字节码

QG 500

清华大神解密JVM与Class文件格式,全面而透彻的教程来了

清华大佬终于把JVM入门以及Class格式的知识讲解透彻了!这份教程是全面而透彻的,将为你揭开JVM和Class文件格式的神秘面纱。不论你是初学者还是有一定经验的开发者,这个教程都能帮助你深入理解JVM的工作原理和Class文件的结构。你将学习到JVM内存管理、类加载机制、字节码解析等核心知识。更值得一提的是,这个教程是由清华大佬亲自讲解,保证了内容的权威性和可靠性。立即开始你的JVM与Class文件格式的探索之旅吧!

jjc4261的博客 139

java虚拟机栈线程共享吗_解密JVM虚拟机底层原理【 虚拟机栈】

前言文章奔着简洁易懂的形式去写,不会有很多花哨的废话,尽可能简明扼要的描述清楚想要表达的一些东西,如果你想深入了解JVM底层,不妨花几分钟仔细看看昨天说过了 程序计数器 特点以及作用 今天接着说虚拟机栈说起栈内存,可能很多人比较熟悉,什么栈内存溢出啊,递归啊,等。。。。。。那今天就来带着大家一起详细的解读一下栈内存的相关知识虚拟机栈 定义Java Virtual Machine Stacks (J...

weixin_39959615的博客 361

[解密JVM-02] 类加载机制

了解类的加载机制和相应的几个阶段

学哥斌的博客 204

深入探索JDK:Java开发工具包的奥秘

JDK是Java开发工具包的简称,是Java语言的软件开发工具包,主要用于Java程序的开发、编译、运行和调试。JDK包含了Java的运行环境(Java Runtime Environment,简称JRE)和Java的一些实用工具(如javac、java、javadoc等)。此外,JDK还提供了Java API类库,这是Java应用程序编程接口,为Java应用提供了很多现成的类,可以直接引用。JDK作为Java编程的基础工具包,在Java程序的开发、编译、运行和调试等方面发挥着重要作用。

种一棵树,最好的时间是十年前,其次是现在。 1581
上一篇: “深入探索JVM内部机制:揭秘Java虚拟机“
下一篇: “深入探究JVM内部机制:从字节码到实际执行“
爱编程的小土豆
博客等级 码龄3年 20粉丝 217原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

爱编程的小土豆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值