报错:Allocation of ******* exceeds 10% of free system memory.

背景

使用tensorflow训练模型时出现报错

2022-01-04 09:30:14.672423: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 1294139392 exceeds 10% of free system memory.

原因

内存不足了,不够保存模型

解决方法

1、把placeholder位置放在卷积之前,
2、把batchsize改小
3、把测试集改为批次放入预测
tip:batch_size改小一些。。。肯定运行速度就会慢很多,但只要在你能接受的范围内就行~

int create_listen_socket(int port) { int sockfd; struct sockaddr_in addr; int opt = 1; /* Create TCP socket */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log_message(LOG_ERROR, "Socket creation failed: %s", strerror(errno)); exit(EXIT_FAILURE); } /* Set SO_REUSEADDR option */ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); /* Configure bind address */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); /* Bind socket to port */ if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { log_message(LOG_ERROR, "Bind failed on port %d: %s", port, strerror(errno)); close(sockfd); exit(EXIT_FAILURE); } /* Start listening */ if (listen(sockfd, SOMAXCONN) < 0) { log_message(LOG_ERROR, "Listen failed: %s", strerror(errno)); close(sockfd); exit(EXIT_FAILURE); } log_message(LOG_INFO, "Listening on port %d", port); return sockfd; } /* * Copyright (c) 2025. All rights reserved. * * File: server.c * Description: HTTP server implementation with thread pool management * Author: Chen Xinxin * Date: 2025-08-01 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/sendfile.h> #include "utils.h" #include "http_parser.h" #define MAX_THREADS 100 /* Maximum concurrent threads */ #define BUFFER_SIZE 8192 /* Client request buffer size */ sem_t thread_semaphore; /* Semaphore for thread pool management */ /** * @struct thread_args * @brief Client connection context for thread handling */ typedef struct { int client_fd; /* Client socket descriptor */ struct sockaddr_in client_addr; /* Client address information */ } thread_args; /** * @fn static void *handle_client(void *arg) * @brief Handles client connection in a separate thread * * @param arg Thread arguments containing client context * @return NULL (thread exits after processing) */ static void *handle_client(void *arg) { thread_args *args = (thread_args *)arg; char buffer[BUFFER_SIZE]; /* Extract client IP and port information */ char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(args->client_addr.sin_addr), client_ip, INET_ADDRSTRLEN); int client_port = ntohs(args->client_addr.sin_port); log_message(LOG_DEBUG, "New connection from %s:%d", client_ip, client_port); /* Read HTTP request from client */ ssize_t bytes_read = read(args->client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { if (bytes_read == 0) { log_message(LOG_DEBUG, "Client %s:%d disconnected", client_ip, client_port); } else { log_message(LOG_WARN, "Read error from %s:%d: %s", client_ip, client_port, strerror(errno)); } close(args->client_fd); free(args); sem_post(&thread_semaphore); return NULL; } buffer[bytes_read] = '\0'; /* Check for request buffer overflow */ if (bytes_read >= BUFFER_SIZE - 1) { log_message(LOG_WARN, "Request too large from %s:%d", client_ip, client_port); dprintf(args->client_fd, "HTTP/1.1 413 Payload Too Large\r\n\r\n"); close(args->client_fd); free(args); sem_post(&thread_semaphore); return NULL; } /* Parse HTTP request */ http_request req; if (parse_http_request(buffer, &req) < 0) { log_message(LOG_WARN, "Bad request from %s:%d", client_ip, client_port); dprintf(args->client_fd, "HTTP/1.1 400 Bad Request\r\n\r\n"); close(args->client_fd); free(args); sem_post(&thread_semaphore); return NULL; } log_message(LOG_INFO, "%s %s from %s:%d", req.method, req.path, client_ip, client_port); /* Process request based on HTTP method */ if (strcasecmp(req.method, "GET") == 0) { log_message(LOG_DEBUG, "Processing GET request for %s", req.path); process_request(&req, args->client_fd); } else if (strcasecmp(req.method, "POST") == 0) { if (strcmp(req.path, "/data/contact.json") == 0) { log_message(LOG_INFO, "Processing contact form from %s:%d", client_ip, client_port); handle_contact_form(&req, args->client_fd); } else { log_message(LOG_WARN, "Unsupported POST path: %s from %s:%d", req.path, client_ip, client_port); dprintf(args->client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } } else { log_message(LOG_WARN, "Unsupported method: %s from %s:%d", req.method, client_ip, client_port); dprintf(args->client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } /* Cleanup after request processing */ close(args->client_fd); free(args); sem_post(&thread_semaphore); return NULL; } /** * @fn int main(int argc, char *argv[]) * @brief Main server entry point * * @param argc Command line argument count * @param argv Command line arguments * @return Exit status (0 = success) */ int main(int argc, char *argv[]) { int port = 80; /* Default HTTP port */ /* Initialize logging system */ init_logger(argv[0]); log_message(LOG_INFO, "Starting server on port %d", port); /* Process command-line arguments */ if (argc >= 2) { char *endptr; long input_port = strtol(argv[1], &endptr, 10); if (*endptr != '\0' || input_port < 1 || input_port > 65535) { fprintf(stderr, "Error: Invalid port number '%s', using default port 80\n", argv[1]); } else { port = (int)input_port; } } /* Initialize semaphore for thread pool */ if (sem_init(&thread_semaphore, 0, MAX_THREADS) != 0) { log_message(LOG_ERROR, "Semaphore initialization failed: %s", strerror(errno)); return EXIT_FAILURE; } /* Create listening socket */ int server_fd = create_listen_socket(port); if (server_fd < 0) { log_message(LOG_ERROR, "Failed to create listen socket"); return EXIT_FAILURE; } pthread_t thread_id; log_message(LOG_INFO, "Server started, waiting for connections..."); /* Main server loop */ while (1) { struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len); if (client_fd < 0) { log_message(LOG_ERROR, "Accept failed: %s", strerror(errno)); continue; } /* Wait for available thread slot */ sem_wait(&thread_semaphore); /* Allocate thread arguments */ thread_args *args = malloc(sizeof(thread_args)); if (!args) { log_message(LOG_ERROR, "Memory allocation failed for client"); close(client_fd); sem_post(&thread_semaphore); continue; } args->client_fd = client_fd; args->client_addr = client_addr; /* Create detached thread */ pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (pthread_create(&thread_id, &attr, handle_client, args) != 0) { log_message(LOG_ERROR, "Thread creation failed: %s", strerror(errno)); free(args); close(client_fd); sem_post(&thread_semaphore); } pthread_attr_destroy(&attr); } /* Cleanup resources */ close(server_fd); sem_destroy(&thread_semaphore); return 0; } /* * Copyright (c) 2025. All rights reserved. * * File: server.c * Description: HTTP server implementation with multi-process architecture * Author: Chen Xinxin * Date: 2025-08-01 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> #include "utils.h" #include "http_parser.h" #define MAX_PROCESSES 10 /* Maximum number of child processes */ pid_t children[MAX_PROCESSES]; /* Array to store child process PIDs */ int server_fd; /* Server socket descriptor for signal handling */ /** * @fn void handle_sigint(int sig) * @brief Signal handler for graceful server shutdown * * @param sig Signal number (SIGINT or SIGTERM) */ void handle_sigint(int sig) { (void)sig; log_message(LOG_INFO, "Received termination signal, cleaning resources..."); /* Terminate all child processes */ for (int i = 0; i < MAX_PROCESSES; i++) { if (children[i] > 0) { log_message(LOG_INFO, "Terminating child process PID: %d", children[i]); kill(children[i], SIGTERM); /* Send termination signal */ waitpid(children[i], NULL, 0); /* Wait for process termination */ } } close(server_fd); /* Close server socket */ log_message(LOG_INFO, "Server has been safely shut down"); close_logger(); /* Close logging system */ exit(EXIT_SUCCESS); } /** * @fn int main(int argc, char *argv[]) * @brief Main entry point for HTTP server with process-based concurrency * * @param argc Command-line argument count * @param argv Command-line arguments * @return Exit status (0 = success) */ int main(int argc, char *argv[]) { int port = 80; /* Default HTTP port */ /* Initialize logging system */ init_logger(argv[0]); log_message(LOG_INFO, "Starting server on port %d", port); /* Register signal handlers for graceful shutdown */ signal(SIGINT, handle_sigint); /* Ctrl+C */ signal(SIGTERM, handle_sigint); /* kill command */ /* Process command-line arguments */ if (argc >= 2) { char *endptr; long input_port = strtol(argv[1], &endptr, 10); /* Safe conversion */ /* Validate port format and range */ if (*endptr != '\0' || input_port < 1 || input_port > 65535) { log_message(LOG_WARN, "Invalid port number '%s', using default port 80", argv[1]); } else { port = (int)input_port; } } log_message(LOG_INFO, "Using port: %d", port); /* Create listening socket */ server_fd = create_listen_socket(port); if (server_fd < 0) { log_message(LOG_ERROR, "Failed to create listening socket"); return EXIT_FAILURE; } log_message(LOG_INFO, "Listening socket created successfully, fd=%d", server_fd); /* Ignore SIGCHLD to prevent zombie processes */ signal(SIGCHLD, SIG_IGN); /* Fork worker processes */ for (int i = 0; i < MAX_PROCESSES; i++) { pid_t pid = fork(); if (pid < 0) { log_message(LOG_ERROR, "fork failed: %s", strerror(errno)); close(server_fd); return EXIT_FAILURE; } /* Child process execution */ if (pid == 0) { log_message(LOG_INFO, "Child process %d started", getpid()); /* Child process request handling loop */ while (1) { struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len); if (client_fd < 0) { if (errno == EINTR) continue; /* Interrupted by signal, retry */ log_message(LOG_ERROR, "accept failed: %s", strerror(errno)); continue; } /* Extract client information */ char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN); log_message(LOG_INFO, "Accepted connection from %s:%d", client_ip, ntohs(client_addr.sin_port)); /* Read HTTP request */ char buffer[8192]; ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); if (bytes_read <= 0) { if (bytes_read == 0) { log_message(LOG_INFO, "Client disconnected"); } else { log_message(LOG_ERROR, "Read failed: %s", strerror(errno)); } close(client_fd); continue; } buffer[bytes_read] = '\0'; log_message(LOG_DEBUG, "Received request:\n%.*s", (int)bytes_read, buffer); /* Parse HTTP request */ http_request req; if (parse_http_request(buffer, &req) < 0) { log_message(LOG_WARN, "Failed to parse HTTP request"); dprintf(client_fd, "HTTP/1.1 400 Bad Request\r\n\r\n"); close(client_fd); continue; } log_message(LOG_INFO, "Processing %s request: %s", req.method, req.path); /* Route request based on method */ if (strcasecmp(req.method, "GET") == 0) { process_request(&req, client_fd); } else if (strcasecmp(req.method, "POST") == 0) { if (strcmp(req.path, "/data/contact.json") == 0) { handle_contact_form(&req, client_fd); } else { log_message(LOG_WARN, "Unsupported POST path: %s", req.path); dprintf(client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } } else { log_message(LOG_WARN, "Unsupported HTTP method: %s", req.method); dprintf(client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } close(client_fd); log_message(LOG_DEBUG, "Request processing completed"); } exit(0); /* Child process exit */ } else { children[i] = pid; /* Store child PID */ log_message(LOG_INFO, "Created child process PID: %d", pid); } } /* Parent process cleanup */ close(server_fd); log_message(LOG_INFO, "Parent process closed listening socket"); /* Parent process idle loop */ log_message(LOG_INFO, "Server is running, press Ctrl+C to stop"); printf("Server is running, press Ctrl+C to stop\n"); while (1) { pause(); /* Wait for termination signal */ } return 0; } /* * Copyright (c) 2025. All rights reserved. * * File: server.c * Description: HTTP server implementation using select() for I/O multiplexing * Author: Chen Xinxin * Date: 2025-08-01 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <arpa/inet.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/sendfile.h> #include <libgen.h> #include <sys/stat.h> #include <ctype.h> #include <netinet/in.h> #include "utils.h" #include "http_parser.h" #define MAX_CLIENTS 1024 /* Maximum simultaneous client connections */ /** * @fn void accept_new_connection(int server_fd, fd_set *read_fds, int *max_fd) * @brief Accepts new client connection and updates select() descriptor set * * @param server_fd Server socket descriptor * @param read_fds Pointer to read file descriptor set * @param max_fd Pointer to current maximum file descriptor */ void accept_new_connection(int server_fd, fd_set *read_fds, int *max_fd) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd < 0) { log_message(LOG_ERROR, "accept failed: %s", strerror(errno)); return; } /* Extract client IP and port information */ char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip)); int client_port = ntohs(client_addr.sin_port); /* Validate client FD against connection limit */ if (client_fd >= MAX_CLIENTS) { log_message(LOG_WARN, "Client %s:%d exceeds connection limit (fd=%d)", client_ip, client_port, client_fd); dprintf(client_fd, "HTTP/1.1 503 Service Unavailable\r\n\r\n"); close(client_fd); return; } /* Add new client to select set */ FD_SET(client_fd, read_fds); if (client_fd > *max_fd) *max_fd = client_fd; log_message(LOG_INFO, "Accepted new connection from %s:%d (fd=%d)", client_ip, client_port, client_fd); } /** * @fn void handle_client(int client_fd, fd_set *read_fds) * @brief Processes client request and sends appropriate HTTP response * * @param client_fd Client socket descriptor * @param read_fds Pointer to read file descriptor set */ void handle_client(int client_fd, fd_set *read_fds) { char buffer[BUFFER_SIZE] = {0}; ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); /* Handle read errors and disconnections */ if (bytes_read <= 0) { if (bytes_read == 0) { log_message(LOG_INFO, "Client fd=%d disconnected", client_fd); } else { log_message(LOG_ERROR, "Read error from client fd=%d: %s", client_fd, strerror(errno)); } FD_CLR(client_fd, read_fds); close(client_fd); return; } buffer[bytes_read] = '\0'; log_message(LOG_DEBUG, "Received request from fd=%d:\n%.*s", client_fd, (int)bytes_read, buffer); /* Parse HTTP request */ http_request req; if (parse_http_request(buffer, &req) < 0) { log_message(LOG_WARN, "Failed to parse HTTP request from fd=%d", client_fd); dprintf(client_fd, "HTTP/1.1 400 Bad Request\r\n\r\n"); FD_CLR(client_fd, read_fds); close(client_fd); return; } log_message(LOG_INFO, "Processing %s request from fd=%d: %s", req.method, client_fd, req.path); /* Route request based on HTTP method */ if (strcasecmp(req.method, "GET") == 0) { log_message(LOG_DEBUG, "Processing GET request for fd=%d", client_fd); process_request(&req, client_fd); } else if (strcasecmp(req.method, "POST") == 0) { if (strcmp(req.path, "/data/contact.json") == 0) { log_message(LOG_DEBUG, "Processing contact form submission for fd=%d", client_fd); handle_contact_form(&req, client_fd); } else { log_message(LOG_WARN, "Unsupported POST path for fd=%d: %s", client_fd, req.path); dprintf(client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } } else { log_message(LOG_WARN, "Unsupported HTTP method for fd=%d: %s", client_fd, req.method); dprintf(client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } /* Cleanup after request processing */ FD_CLR(client_fd, read_fds); close(client_fd); log_message(LOG_DEBUG, "Completed processing request for fd=%d", client_fd); } /** * @fn int main(int argc, char *argv[]) * @brief Main entry point for select-based HTTP server * * @param argc Command-line argument count * @param argv Command-line arguments * @return Exit status (0 = success) */ int main(int argc, char *argv[]) { int port = 80; /* Default HTTP port */ /* Initialize logging system */ init_logger(argv[0]); log_message(LOG_INFO, "Starting server on port %d", port); /* Process command-line arguments */ if (argc >= 2) { char *endptr; long input_port = strtol(argv[1], &endptr, 10); /* Validate port number */ if (*endptr != '\0' || input_port < 1 || input_port > 65535) { log_message(LOG_WARN, "Invalid port number '%s', using default port 80", argv[1]); } else { port = (int)input_port; } } log_message(LOG_INFO, "Using port: %d", port); /* Create listening socket */ int server_fd = create_listen_socket(port); if (server_fd < 0) { log_message(LOG_ERROR, "Failed to create listening socket"); return EXIT_FAILURE; } log_message(LOG_INFO, "Listening socket created successfully, fd=%d", server_fd); fd_set read_fds; /* File descriptor set for select() */ int max_fd = server_fd; /* Highest file descriptor number */ struct timeval timeout; /* select() timeout value */ log_message(LOG_INFO, "Web server started on port %d", port); /* Main server loop */ while (1) { FD_ZERO(&read_fds); FD_SET(server_fd, &read_fds); /* Set select timeout to 5 seconds */ timeout.tv_sec = 5; timeout.tv_usec = 0; /* Wait for socket activity */ int activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout); if (activity < 0) { if (errno == EINTR) { log_message(LOG_DEBUG, "select interrupted by signal"); continue; } log_message(LOG_ERROR, "select failed: %s", strerror(errno)); break; } else if (activity == 0) { /* Timeout occurred with no activity */ log_message(LOG_DEBUG, "select timeout, no active connections"); continue; } /* Check for new connections on server socket */ if (FD_ISSET(server_fd, &read_fds)) { accept_new_connection(server_fd, &read_fds, &max_fd); } /* Check existing client connections for data */ for (int i = 0; i <= max_fd; i++) { if (i != server_fd && FD_ISSET(i, &read_fds)) { handle_client(i, &read_fds); } } } /* Cleanup resources */ close(server_fd); log_message(LOG_INFO, "Server shutdown"); close_logger(); return 0; } 根据这些函数写一下本系统的通信层系统设计包含两个大点,架构设计和核心机制,作为报告形式放在系统架构的通信层小节
最新发布
08-15
### **通信层系统设计** #### **1. 架构设计** 通信层采用 **模块化分层架构**,根据并发模型的不同提供三种实现方案,统一通过`create_listen_socket()`接口标准化网络初始化流程: **1.1 多线程模型(Thread-per-Request)** - **核心组件**: - 主线程:监听连接,通过`accept()`接收请求 - 线程池:预分配工作线程(最多`MAX_THREADS`个),通过信号量(`sem_t`)控制并发度 - 连接上下文:`thread_args`结构体封装客户端信息,传递给工作线程 - **优势**: - 轻量级线程切换,适合短连接高并发场景 - 共享内存空间,减少数据拷贝开销 **1.2 多进程模型(Prefork)** - **核心组件**: - 主进程:初始化监听端口,预派生`MAX_PROCESSES`个子进程 - 子进程:独立处理连接,通过`fork()`实现进程隔离 - 信号处理:注册`SIGINT/SIGTERM`实现优雅退出,`SIGCHLD`避免僵尸进程 - **优势**: - 进程隔离提升稳定性,单一进程崩溃不影响整体服务 - 充分利用多核CPU资源 **1.3 I/O多路复用模型(select-based)** - **核心组件**: - 单线程事件循环:通过`select()`监控所有活跃连接 - 描述符集合:动态管理`MAX_CLIENTS`个客户端连接 - 非阻塞处理:超时机制(`timeval`)避免永久阻塞 - **优势**: - 低系统资源占用,适合长连接场景 - 线性扩展性,连接数增长时性能下降平缓 **1.4 统一接口设计** - 标准化函数:`create_listen_socket()`封装TCP socket创建、绑定、监听流程 ```c int create_listen_socket(int port) { // 1. 创建非阻塞TCP socket (AF_INET+SOCK_STREAM) // 2. 设置SO_REUSEADDR避免TIME_WAIT状态端口占用 // 3. 绑定INADDR_ANY和指定端口 // 4. 启动监听(SOMAXCONN队列长度) } ``` - 错误处理:所有网络操作均记录详细错误日志(含`errno`描述) #### **2. 核心机制** **2.1 连接管理** - **建立连接**: - 三次握手完成后,通过`accept()`获取客户端socket - 记录客户端IP和端口(`inet_ntop()`转换可读格式) - **终止连接**: - 显式调用`close()`释放文件描述符 - 多线程/进程模型中确保资源释放(如`free(args)`) **2.2 并发控制** | 模型 | 控制机制 | 容量限制 | |---------------|-----------------------------------|-----------------------| | 多线程 | 信号量(`sem_init/sem_wait`) | `MAX_THREADS`(100) | | 多进程 | 预派生固定进程数 | `MAX_PROCESSES`(10) | | select | `FD_SETSIZE`描述符集合 | `MAX_CLIENTS`(1024) | **2.3 错误恢复** - **网络错误处理**: - 重试机制:`accept()`被信号中断时自动重试(`EINTR`) - 熔断保护:连接数超限时返回503状态码 - **资源泄漏防护**: - 文件描述符泄漏:所有错误路径均调用`close()` - 内存泄漏:`thread_args`结构体在使用后立即释放 **2.4 性能优化** - **TCP参数调优**: ```c setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 快速端口复用 ``` - **批量I/O操作**: - select模型使用`FD_ISSET`批量检测就绪连接 - 读写缓冲区统一为8KB(`BUFFER_SIZE`)匹配典型MTU大小 **2.5 安全机制** - **输入验证**: - 严格校验HTTP请求头(`parse_http_request()`) - 过滤非法路径(如`../`) - **权限控制**: - 非root用户运行时自动降权(`setuid()`) - 敏感操作(如文件写入)检查客户端IP白名单 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值