操作系统八股文

操作系统八股文

第一章 操作系统概述

1.1 操作系统概念

操作系统是指控制和管理整个计算机系统的硬件和软件资源,位于两者之间,能够合理地组织调度计算机地工作和资源的分配,以提供给用户和其他软件方便的接口和环境,是计算机系统中最基本的系统软件

1.2 用户态和内核态

  • 用户态:用户态运行的进程可以直接读取用户程序的数据
  • 内核态:内核态运行的进程几乎可以访问计算机的任何资源

1.3 用户态切换到内核态有哪些方法

  • 系统调用:用户态进程通过系统调用申请使用操作系统提供的服务完成工作。如fork()函数实际上执行的是创建进程的系统调用。
  • 异常:当CPU在执行用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态。比如缺页异常
  • 中断:当外围设备完成用户请求的操作后,会向CPU发送相应的中断信号,这时CPU会暂停执行下一条指令转而去执行与中断信号对应的处理程序。如果先前执行的指令在用户态,那么这个转换过程自然地发生了用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作。

1.4 系统调用的概念和分类

用户态进程切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务完成工作。

凡是与内核态资源有关的操作都需要使用系统调用,可以分为以下几类:

  • 设备管理:完成设备的请求或释放,以及启动等功能
  • 文件管理:完成文件的读、写、创建及删除等功能
  • 进程控制:完成进程的创建、撤销、阻塞、唤醒等功能
  • 进程通信:完成进程间消息传递或信号传递等功能
  • 内存管理:完成内存的分配、回收等功能

fopen函数、exit函数必须进入内核才能完成

第二章 进程管理

2.1 什么是进程

编译后的可执行文件只是存储在硬盘的静态文件,运行时被加载到内存,CPU执行内存中指令,这个运行程序被称为进程。进程是对运行时程序的封装,是操作系统进行资源调度和分配的基本单位。

2.2 PCB是什么

为了使参与并发执行的每个程序包含的数据都能独立运行,在操作系统中为其配置一个专门的数据结构,称为进程控制块PCB,PCB是进程存在的唯一标志。包括以下信息:

  • 进程描述信息:进程标识符、用户标识符
  • 进程控制和管理信息:进程状态、进程优先级等
  • 进程资源分配清单:虚拟内存地址空间信息、打开文件列表、IO设备信息
  • CPU相关信息:当进程进行切换时,CPU寄存器值保存在PCB,以便CPU重新执行进程时能从断点处继续执行。

2.3 进程状态及切换

  • 创建态:分配资源、初始化PCB
  • 就绪态:拥有了除了CPU之外的所有资源,万事俱备,只欠CPU
  • 运行态:占有CPU,几核CPU则每一时刻最多有几个进程处于运行状态
  • 阻塞态:因等待某一事件而不能运行,CPU是计算机最贵的部件,为了提高CPU利用率,进程获得其他资源后才能得到CPU的服务
  • 终止态:回收资源、撤销PCB

另外两种状态

阻塞挂起状态: 进程在外存(硬盘)并等待某个事件的出现

就绪挂起状态: 进程在外存(硬盘),但只要进入内存,马上运行

在这里插入图片描述

2.4 进程调度算法(高频)

  • 先来先服务(FCFS): 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU时再重新调度。
  • 短作业优先(SJF):从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
  • 高响应比优先(HRRN):从就绪队列中选出一个响应比最高的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。(响应比 = (等待时间 + 要求服务时间) / 要求服务时间
  • 时间片轮转(RR):按照进程到达就绪队列的顺序,轮流让各个进程执行一个时间片,适用于分时操作系统
  • 优先级调度算法:为各个进程分配优先级,首先执行最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。
  • 多级反馈队列:既能使高优先级的进程得到响应又能使短进程迅速完成,是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。
    1. 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
    2. 新进程达到时先进入第1级队列,按照FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾(若已经在最下级队列,则重新放回该队列队尾)
    3. 只有第k级队列为空时,才会为k+1级队头的进程分配时间片

先来先服务(FCFS)、短作业优先(SJF)、高响应比优先(HRRN)属于非抢占式算法;时间片轮转(RR)、多级反馈队列属于抢占式算法;优先级调度算法既可以是抢占式算法又可以是非抢占式算法。

先来先服务(CFCS)、高响应比优先(HRRN)、时间片轮转(RR)不会导致饥饿,短作业优先(SJF)、优先级调度算法和多级反馈队列会导致饥饿。

2.5 进程间通信方式(高频)

  1. 匿名管道(pipe)半双工(同一时刻数据只能在一个方向流动)、只能一端写一端读、不是普通文件只存在内存中、一次性操作。由于没有名字,只能用于父子间进程通信。
  2. 有名管道(FIFO):克服了匿名管道只能用于父子的进程间通信的缺点,严格遵循先进先出,以磁盘文件的方式存在,可以实现本机任意两个进程通信。
  3. 信号: 信号是一种比较复杂的通信方式,信号可以在任何时候发给某一进程,而无需知道该进程的状态。
  4. 信号量:信号量是一个计数器,用于多进程对共享数据的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源,主要作为进程间的同步手段。
  5. 消息队列:本质上是保存在内核中的消息链表,可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取消息队列。克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  6. 共享内存:映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式。
  7. **Socket:**不同主机间的进程通信

在这里插入图片描述

2.6 守护进程

定义:守护进程是指在后台运行的,没有控制终端,周期性地执行某种任务,Linux 的大多数服务器就是用守护进程实现。

创建方法:

  1. 通过fork创建子进程,并退出父进程
  2. 调用setsid利用子进程创建一个会话(守护进程需要摆脱父进程的影响,setsid调用后,进程成为新的会话组长和进程组长)
  3. 禁止进程重新打开控制终端(由于该进程可以申请打开终端,为了避免这种情况,可再次通过fork创建子进程,使原来进程不再是会话组长)
  4. 关闭不再需要的文件描述符(避免资源浪费)
  5. 将当前目类改为根目录
  6. 清除进程的umask以确保当守护进程创建文件和目录时拥有所需的权限。
  7. 业务逻辑

2.7 僵尸进程(高频)

定义:子进程已死,但父进程未回收其资源,此时子进程变为僵尸进程。

优点:设置僵尸进程的目的是维护子进程信息(进程ID、进程终止状态、CPU使用时间等),以便父进程在以后某个时间调用wait/waitpid获取。

缺点:僵尸进程会占用内核资源,且系统所用的进程号有限,如果有大量的僵尸进程会导致系统不能生产新进程。

结束僵尸进程的比较好的方式:子进程结束时, 父进程会收到SIGCHLD信号。父进程通过signal(SIGCHLD, SIG_IGN)通知内核对子进程的结束不关心,可让内核把僵尸子进程转交给init进程去处理。

第三章 线程

3.1 进程和线程的区别?(高频)

一个进程可以产生多个线程,进程和线程有以下区别:

  • 调度:进程是资源管理的基本单位, 线程是程序执行的基本单位。
  • 拥有资源: 进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问隶属于进程的资源。
  • 系统开销: 创建或撤销进程时,系统都要为之分配或回收系统资源,开销显著大于线程开销。
  • 切换:线程上下文切换比进程上下文切换要快得多。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。

3.2 为什么虚拟地址空间切换会比较耗时?

把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用Cache来缓存常用的地址映射,这样可以加速页表查找,这个Cache就是TLB。

由于每个进程都有自己的虚拟地址空间,因此每个进程都有自己的页表,那么当进程切换后页表也要进行切换,TLB就失效了,Cache失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换无需切换地址空间,因此线程切换要比较进程切换快。

3.3 线程和协程的区别

  • 一个线程可以拥有多个协程,协程是一种用户态的轻量级线程,协程的调度完全由用户控制,不被操作系统内核所管理。
  • 线程是抢占式,而协程是非抢占式的,需要用户释放使用权切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。

3.4 线程同步和线程互斥

  • 线程同步:也称为直接制约关系,它是指为完成某种任务而建立的两个或多个线程,因为需要协调这些线程的工作次序而产生的制约关系。
  • 线程互斥:也称为间接制约关系,当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。线程互斥可以看成是一种特殊的线程同步。

3.5 生产者和消费者模型

  • 在缓冲区为空时,消费者不能再进行消费
  • 在缓冲区为满时,生产者不能再进行生产
/* 
利用互斥锁和信号量实现生产者和消费者模型
- 一对同步信号量和两对异步信号量
- 实现互斥的P操作(互斥锁)一定要在实现同步的P操作(条件变量)之后,否则会出现死锁情况;两个V操作顺序可以替换
*/
#include 
#include 
#include 
#include 
#include 

// 创建一个互斥量
pthread_mutex_t mutex;
// 创建两个信号量
sem_t psem;
sem_t csem;

struct Node{
    int num;
    struct Node* next;
};

// 头结点
struct Node* head = NULL;

void* producer(void* arg) {

    // 不断的创建新的节点,添加到链表中
    while(1) {
        sem_wait(&psem);
        pthread_mutex_lock(&mutex);
        struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->next = head;
        head = newNode;
        newNode->num = rand() % 1000;
        printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
        pthread_mutex_unlock(&mutex);
        sem_post(&csem);
    }

    return NULL;
}

void * customer(void * arg) {

    while(1) {
        sem_wait(&csem);
        pthread_mutex_lock(&mutex);
        // 保存头结点的指针
        struct Node * tmp = head;
        head = head->next;
        printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
        free(tmp);
        pthread_mutex_unlock(&mutex);
        sem_post(&psem);
       
    }
    return  NULL;
}

int main() {

    pthread_mutex_init(&mutex, NULL);
    sem_init(&psem, 0, 8);
    sem_init(&csem, 0, 0);

    // 创建5个生产者线程,和5个消费者线程
    pthread_t ptids[5], ctids[5];

    for(int i = 0; i < 5; i++) {
        pthread_create(&ptids[i], NULL, producer, NULL);
        pthread_create(&ctids[i], NULL, customer, NULL);
    }

    for(int i = 0; i < 5; i++) {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }

    while(1) {
        sleep(10);
    }

    pthread_mutex_destroy(&mutex);

    pthread_exit(NULL);

    return 0;
}

3.6 什么是死锁?死锁产生的必要条件?如何解决死锁?(高频)

死锁:如果一个线程集合中的每一个线程都在等待只能由该线程集合中的其他线程才能引发的事件,则该线程集合就是死锁。

必要条件:

  • 互斥条件:必须对互斥使用的资源争抢,如打印设备;而内存、扬声器可以同时让多个进程使用的资源不会导致死锁
  • 不剥夺条件:线程的资源不能由其他线程强行剥夺,只能主动释放
  • 请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他线程占有
  • 循环等待条件:存在线程资源循环等待链(循环等待不一定会导致死锁,死锁一定会导致循环等待)

解决死锁:有预防,避免,检测、解除、鸵鸟策略

  • 预防:限制并发线程对资源的请求。
  • 避免:系统在分配资源时,根据资源的使用情况提前做出预测,从而避免死锁的发生
  • 检测:系统设有专门的机构,当死锁发生时,该机构能够检测死锁的发生,并精确地确定与死锁有关的线程和资源。
  • 解除:是与检测相配套的一种措施,用于将进程从死锁状态下解脱出来
  • 鸵鸟策略:把头埋在沙子里,假装根本没发生问题。因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任何措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。

如果线程0加了锁0和锁1,线程1也加了锁0和锁1,可能会发生死锁,解决方法有:

顺序加锁

mutex m0,m1;
int i = 0;
void fun0()
{
	while (i < 100)
	{
		lock_guard g0(m0);  //线程0加锁0
		lock_guard g1(m1);  //线程0加锁1
		cout << "thread 0 running..." << endl;
	}
	return;
}
void fun1()
{
	while (i < 100)
	{
                lock_guard g0(m0);  //线程1加锁0
		lock_guard g1(m1);  //线程1加锁1
		cout << "thread 1 running...   "<< i << endl;
	}
	return;
}
int main()
{
	thread p0(fun0);
	thread p1(fun1);
	p0.join();
	p1.join();
	return 0;
}

3.7 线程中常用的锁,有哪几种

  1. 互斥锁:为了避免多个线程在某一时刻同时操作一个共享资源。例如线程池中有多个空闲线程和一个任务队列,每个线程都会使用互斥锁互斥访问任务队列,以避免多个线程同时访问任务队列发生错乱。(pthread_mutex_t
  2. 条件锁:即条件变量,某一个线程因为某个条件未满足时,可以使用条件变量使改程序处于阻塞状态。一旦条件满足会以信号量的方式唤醒一个因为该条件而被阻塞的线程。例如线程池中起初任务队列为空,线程池中的线程因为任务队列为空这个条件处于阻塞状态。一旦有任务进来,就会以信号量的方式唤醒一个线程来处理这个任务。(pthread_cond_t
  3. 自旋锁:如果一个线程想要获取一个被使用的自旋锁,那么它会一直占用CPU请求这个自旋锁,使得CPU不能去做其他事情,直到获取这个锁为止。例如计算机上运行的程序中有两个线程T1和T2,分别在处理器core1和core2上运行,两个线程之间共享着一个资源,如果T1正在使用自旋锁,而T2也去申请这个自旋锁,T2的处理器core2会一直不断地循环检查锁是否可用,直到获取到这个自旋锁为止。(spinlock_t)(与互斥锁不同,如果T2申请互斥锁,T2处于阻塞状态被放入到等待队列中,处理器core2会去处理其他任务而不必一直等待)
  4. 读写锁:计算机中某些数据被多个线程共享,对数据库的操作有两种:一种是读操作,从数据库中读取数据不会修改数据库中内容;另一种是写操作,会修改数据库中存放的数据。读写锁允许在数据库上同时执行多个“读”操作,但是某一时刻只能在数据库上有一个“写”操作来更新数据

第四章 内存管理(高频)

4.1 内存管理到底是干什么的

主要负责内存的分配与回收(malloc函数:申请内存,free函数:释放内存),另外也负责地址转换,将逻辑地址转换成相应的物理地址

4.2 内存管理机制有哪些

简单分为连续分配管理方式和非连续分配管理方式:连续分配管理方式指一个用户程序分配一个连续的内存空间,如块式管理;非连续分配管理方式允许一个用户程序使用的内存分布在离散或者不相邻的内存中,如页式管理、段式管理

  • 块式管理:将内存分为几个固定大小的块,每个块只包含一个进程。若程序运行只需要很小的空间,分配的这块大内存有很大一部分被浪费,产生很多内部碎片
  • 页式管理:将内存分为大小相等的分区,分区相比于块的划分粒度更小。每个分区称为一个页框,每个页框都有编号称为页框号,从0开始编址;将用户进程的地址空间也分为与页框大小相等的分区,称为,每个页也有编号称为页号,从0开始编址。os以页框为单位分配内存,每个页不必连续存放。页式管理通过页表对应逻辑地址和物理地址。
  • 段式管理:进程的地址空间按照自身逻辑划分为若干段,每个段都有段名,从0开始编址。os以为单位分配内存,每段在内存中占据连续空间,但各段之间不必连续存放。段式管理通过段表对应逻辑地址和物理地址。
  • 段页式管理:先分段后分页

4.3 分页、分段的共同点、不同点及优缺点

共同点:

  • 都是为了提高内存利用率,减少内部碎片
  • 页和段都是离散存储的,所以两者都是离散分配内存,但每个页和段内连续

不同点:

  • 页大小固定由操作系统决定,段大小不固定取决于当前程序
  • 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段、数据段,能够更好的满足用户的需求。

优缺点:

  • 分页管理:优点是内存空间利用率高,不会产生外部碎片,只会有少部分的内部碎片。缺点是不方便实现信息的共享与保护
  • 分段管理:优点是方便按照逻辑模块实现信息的共享与保护。缺点是如果段长太长会产生外部碎片

4.4 快表是什么?

快表TLB是一种缓存机制,用于加速虚拟内存到物理内存地址的转换。当CPU访问内存时,会先尝试从TLB中查找相应的内存地址是否已经被缓存。

如果TLB中存在该内存地址映射,CPU就可以直接使用这个映射而不必访问内存管理单元(MMU)进行地址转换。这种方式比每次都访问MMU进行地址转换要快得多,因为TLB通常被设计成位于CPU内部或者非常接近CPU,可以直接从快速缓存中访问。

如果CPU在TLB中找不到所需的内存地址映射,则需要向MMU发出请求,获取该地址的物理内存地址,然后把该映射添加到TLB中。由于TLB大小有限,当TLB中的所有项都被使用并且没有可用项时,CPU需要把一些现有的TLB项淘汰以腾出空间。

快表通常被用于支持虚拟内存系统,在这种系统中,每个进程都认为它有自己的一块连续内存地址空间,但实际上他们共享物理内存。TLB的作用是把虚拟地址转换为物理地址,从而支持多个进程同时使用物理内存。

4.5 什么是多级页表

多级页表是一种用于管理虚拟内存的数据结构,他把虚拟地址空间划分成多个层级的页表,每个页表包含一组页表项,每个页表项记录了虚拟地址与物理地址之间的映射关系。

多级页表的主要优点是有效地降低页表的空间需求。由于虚拟地址空间非常大,导致单个页表也会非常大,需要大量页表项。使用多级页表,操作系统可以把虚拟地址空间划分成多个部分,每个部分由一个小的页表来管理,这样可以大大降低单个页表的大小。同时,多级页表还可以提高访问页表的效率,因为只有在必要时才需要访问每个级别的页表。

4.6 虚拟内存管理

4.6.1 什么是物理地址和虚拟地址(逻辑地址)?

  • 物理地址指的是计算机内存中的实际物理位置。
  • 虚拟地址是指由CPU生成的地址,他不指向实际物理位置,而是由操作系统将虚拟地址映射到物理地址。

4.6.2 什么是虚拟内存?虚拟内存的优点?

定义:在程序装入时可以将程序中很快会用到的部分转入内存,暂时用不到的部分留在外存;程序执行过程中如果所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存;若内存空间不够,则由操作系统负责将内存中暂时用不到的信息换出到外存。因此在用户看来似乎有一个比实际内存大得多的内存,这就是虚拟内存

虚拟内存的优点:

  1. 提高内存利用率:由于虚拟地址是由操作系统进行映射的,不同的进程可以共享物理内存,从而提高内存利用率
  2. 提高安全性:操作系统可以通过虚拟地址来实现进程间的内存隔离和保护,从而防止恶意程序对其他程序的内存破坏
  3. 简化程序设计:虚拟地址使得程序员可以使用连续的地址空间来访问内存,而不必担心实际的物理地址是如何分配的
  4. 方便内存扩展:操作系统可以在物理内存不足时,将一部分虚拟地址空间映射到硬盘的交换文件中,从而扩展可用内存

4.6.3 虚拟内存的实现方式

  1. 请求分页存储管理:建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。请求分页存储管理系统中,在作业开始运行之前,仅装入当前要执行的部分页即可运行。假如在作业运行过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入主存,同时操作系用也可以将暂时不用的页面置换到外存中。
  2. 请求分段存储管理:建立在分段管理之上,增加了请求段功能和分段置换功能。同请求分页存储管理相同,在作业开始运行前,仅装入当前要执行的部分段即可运行,执行过程中可以将需要的段调入主存,不需要的调出主存
  3. 请求段页式存储管理:建立在段页式管理之上,同样执行过程中需要的段页导入内存,不需要的调出内存。

请求分页与分页存储管理的区别

请求分页存储管理建立在分页管理之上。他们的根本区别是是否将程序所需要的全部地址空间都装入主存。请求分页存储管理不要求全部装入,可以提供虚拟内存,而分页存储管理却不能提供虚拟内存。

4.6.4 页面置换算法有哪些

  1. 最佳页面置换算法(OPT):置换在未来最长时间不访问页面,但是实际系统无法实现,因为程序访问页面是动态的。通常用来衡量算法效率
  2. 先进先出置换算法(FIFO):页面以队列存储,先进入队列的页面先被置换进入磁盘,即淘汰驻留在内存时间最久的页面
  3. 最近最久未使用置换算法(LRU):根据页面未被访问时长用升序列表将页面置换出去。
  4. 时钟页面置换算法:把所有的页面都保存在类似钟面的环形链表中,页面包括一个访问位,当发生缺页异常时,顺时针遍历页面,如果访问位为1,将其改为0,继续遍历,直到访问位为0的页面进行置换。
  5. 最不常用算法(LFU):记录每个页面访问次数,当发生缺页中断时,将访问次数最少的页面置换出去,此方法需要对每个页面访问次数统计,额外开销。

4.7 存储器的层次结构

  • 寄存器:访问速度最快(半个CPU时钟),TLB存放在此。
  • CPU Cache:用的静态随机存储器(SRAM)芯片,有L1、L2、L3共3层(L3不同核之间共享)
  • 内存:用的动态随机存储器(DRAM)芯片
  • SSD/HDD硬盘:断电后数据不会丢失,内存、Cache、寄存器数据断电丢失。

从上到下存储容量越来越大、访问速度越来越慢、成本价格越来越低

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值