简体中文 繁體中文 English Deutsch 한국 사람 بالعربية TÜRKÇE português คนไทย Français Japanese

站内搜索

搜索
AI 风月

活动公告

03-01 22:34
03-01 19:23
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

OpenCV Mat矩阵内存释放实战指南 解决常见内存泄漏问题提升程序稳定性

SunJu_FaceMall

3万

主题

360

科技点

3万

积分

白金月票

碾压王

积分
32696

立华奏

发表于 2025-10-7 12:40:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

OpenCV作为计算机视觉领域最流行的开源库之一,提供了强大的图像处理功能。在OpenCV中,Mat类是用于存储图像和矩阵数据的核心数据结构。然而,不正确的Mat内存管理常常导致内存泄漏、程序崩溃和性能下降等问题。本文将深入探讨OpenCV Mat的内存管理机制,分析常见的内存泄漏场景,并提供实用的解决方案和最佳实践,帮助开发者编写更稳定、高效的OpenCV程序。

OpenCV Mat基础

Mat(Matrix的缩写)是OpenCV中用于表示图像和矩阵的核心类。它包含两部分信息:矩阵头(包含矩阵大小、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵的指针。
  1. // 创建一个Mat对象的基本方法
  2. cv::Mat image; // 默认构造函数,创建一个空的Mat对象
  3. cv::Mat image2(480, 640, CV_8UC3); // 创建一个640x480的3通道彩色图像
  4. cv::Mat image3(480, 640, CV_8UC1, cv::Scalar(0)); // 创建一个640x480的单通道灰度图像,初始化为黑色
复制代码

Mat对象的大小是固定的,不依赖于图像的像素值。这意味着复制Mat对象时,默认情况下只复制矩阵头,而不复制实际的图像数据。这种机制提高了效率,但也可能导致一些内存管理问题。

Mat的内存管理机制

OpenCV的Mat类采用了引用计数机制来管理内存。每个Mat对象都有一个引用计数器,记录有多少个Mat对象共享同一个数据块。
  1. cv::Mat img1 = cv::imread("image.jpg");
  2. cv::Mat img2 = img1; // 只复制矩阵头,img1和img2共享同一数据块
  3. // 此时,img1和img2的引用计数都为2
  4. img2 = cv::Mat(); // img2现在指向空数据,img1的引用计数减1变为1
  5. // 当img1离开作用域时,其引用计数变为0,内存被自动释放
复制代码

当最后一个引用该数据块的Mat对象被销毁时,数据块的内存才会被释放。这种机制大大简化了内存管理,但也需要开发者理解其工作原理,以避免内存泄漏。

常见内存泄漏场景及解决方案

1. 循环中创建Mat对象

在循环中频繁创建Mat对象而不释放,会导致内存持续增长。

问题示例:
  1. void processImages(const std::vector<std::string>& imagePaths) {
  2.     for (const auto& path : imagePaths) {
  3.         cv::Mat img = cv::imread(path);
  4.         // 处理图像...
  5.         // img对象离开作用域时会自动释放,但如果在循环内创建大量临时Mat对象
  6.         // 可能会导致内存峰值过高
  7.     }
  8. }
复制代码

解决方案:
  1. void processImages(const std::vector<std::string>& imagePaths) {
  2.     cv::Mat img; // 在循环外创建Mat对象
  3.     for (const auto& path : imagePaths) {
  4.         img = cv::imread(path); // 重用Mat对象
  5.         // 处理图像...
  6.         // 显式释放内存(可选)
  7.         img.release();
  8.     }
  9. }
复制代码

或者,使用更现代的C++方式:
  1. void processImages(const std::vector<std::string>& imagePaths) {
  2.     for (const auto& path : imagePaths) {
  3.         // 使用局部作用域限制Mat对象的生命周期
  4.         {
  5.             cv::Mat img = cv::imread(path);
  6.             // 处理图像...
  7.         } // img离开作用域,自动释放
  8.     }
  9. }
复制代码

2. 函数间传递Mat对象

在函数间传递Mat对象时,如果不了解OpenCV的内存共享机制,可能导致意外的内存泄漏。

问题示例:
  1. cv::Mat processImage(cv::Mat img) {
  2.     cv::Mat result;
  3.     // 对img进行处理,结果存入result
  4.     cv::cvtColor(img, result, cv::COLOR_BGR2GRAY);
  5.     return result; // 返回result,复制操作可能比预期昂贵
  6. }
  7. void foo() {
  8.     cv::Mat img = cv::imread("image.jpg");
  9.     cv::Mat gray = processImage(img);
  10.     // 使用gray...
  11. } // 所有Mat对象在离开作用域时自动释放
复制代码

虽然上面的代码不会导致内存泄漏,但可能效率不高,因为返回result时可能涉及数据复制。

解决方案:
  1. // 使用引用传递,避免不必要的复制
  2. void processImage(const cv::Mat& img, cv::Mat& result) {
  3.     cv::cvtColor(img, result, cv::COLOR_BGR2GRAY);
  4. }
  5. void foo() {
  6.     cv::Mat img = cv::imread("image.jpg");
  7.     cv::Mat gray;
  8.     processImage(img, gray);
  9.     // 使用gray...
  10. }
复制代码

或者,使用OpenCV的输出参数:
  1. void processImage(cv::InputArray img, cv::OutputArray result) {
  2.     cv::cvtColor(img, result, cv::COLOR_BGR2GRAY);
  3. }
  4. void foo() {
  5.     cv::Mat img = cv::imread("image.jpg");
  6.     cv::Mat gray;
  7.     processImage(img, gray);
  8.     // 使用gray...
  9. }
复制代码

3. 类成员变量中的Mat

当Mat作为类成员变量时,需要特别注意对象的生命周期。

问题示例:
  1. class ImageProcessor {
  2. private:
  3.     cv::Mat image;
  4.    
  5. public:
  6.     void loadImage(const std::string& path) {
  7.         image = cv::imread(path); // 替换旧图像,旧图像内存自动释放
  8.     }
  9.    
  10.     // 其他处理方法...
  11. };
复制代码

上面的代码本身没有问题,但如果在多线程环境中使用,或者ImageProcessor对象生命周期很长,而图像数据很大,可能导致内存占用过高。

解决方案:
  1. class ImageProcessor {
  2. private:
  3.     cv::Mat image;
  4.    
  5. public:
  6.     void loadImage(const std::string& path) {
  7.         // 显式释放旧图像
  8.         image.release();
  9.         image = cv::imread(path);
  10.     }
  11.    
  12.     void clearImage() {
  13.         image.release(); // 显式释放图像内存
  14.     }
  15.    
  16.     // 其他处理方法...
  17. };
复制代码

或者,使用智能指针管理Mat:
  1. class ImageProcessor {
  2. private:
  3.     std::shared_ptr<cv::Mat> imagePtr;
  4.    
  5. public:
  6.     ImageProcessor() : imagePtr(std::make_shared<cv::Mat>()) {}
  7.    
  8.     void loadImage(const std::string& path) {
  9.         *imagePtr = cv::imread(path);
  10.     }
  11.    
  12.     void clearImage() {
  13.         imagePtr->release();
  14.     }
  15.    
  16.     // 其他处理方法...
  17. };
复制代码

4. Mat指针使用不当

直接使用Mat指针而不正确管理内存,是导致内存泄漏的常见原因。

问题示例:
  1. void createMatArray(int size) {
  2.     cv::Mat* matArray = new cv::Mat[size];
  3.     for (int i = 0; i < size; ++i) {
  4.         matArray[i] = cv::Mat(100, 100, CV_8UC3, cv::Scalar(0, 0, 255));
  5.     }
  6.     // 使用matArray...
  7.     // 忘记释放内存,导致内存泄漏
  8. }
复制代码

解决方案:
  1. void createMatArray(int size) {
  2.     std::vector<cv::Mat> matArray(size);
  3.     for (int i = 0; i < size; ++i) {
  4.         matArray[i] = cv::Mat(100, 100, CV_8UC3, cv::Scalar(0, 0, 255));
  5.     }
  6.     // 使用matArray...
  7. } // vector离开作用域,自动释放所有Mat对象
复制代码

如果必须使用指针,请确保正确释放:
  1. void createMatArray(int size) {
  2.     cv::Mat* matArray = new cv::Mat[size];
  3.     for (int i = 0; i < size; ++i) {
  4.         matArray[i] = cv::Mat(100, 100, CV_8UC3, cv::Scalar(0, 0, 255));
  5.     }
  6.     // 使用matArray...
  7.    
  8.     // 正确释放内存
  9.     delete[] matArray;
  10. }
复制代码

更好的方法是使用智能指针:
  1. void createMatArray(int size) {
  2.     std::unique_ptr<cv::Mat[]> matArray(new cv::Mat[size]);
  3.     for (int i = 0; i < size; ++i) {
  4.         matArray[i] = cv::Mat(100, 100, CV_8UC3, cv::Scalar(0, 0, 255));
  5.     }
  6.     // 使用matArray...
  7. } // unique_ptr离开作用域,自动释放内存
复制代码

5. 不正确的Mat复制和克隆

不正确地复制或克隆Mat对象可能导致意外的内存共享或内存泄漏。

问题示例:
  1. void processImages() {
  2.     cv::Mat src = cv::imread("image.jpg");
  3.    
  4.     // 错误:只复制矩阵头,src和dst共享同一数据块
  5.     cv::Mat dst = src;
  6.    
  7.     // 修改dst也会影响src
  8.     dst.setTo(cv::Scalar(0, 0, 0));
  9.     // 现在src也是全黑的
  10.    
  11.     // 另一个错误:在循环中创建临时Mat对象
  12.     for (int i = 0; i < 100; ++i) {
  13.         cv::Mat temp = src.clone(); // 每次循环都分配新内存
  14.         // 处理temp...
  15.     } // 循环结束后,所有temp对象被释放,但可能导致内存峰值过高
  16. }
复制代码

解决方案:
  1. void processImages() {
  2.     cv::Mat src = cv::imread("image.jpg");
  3.    
  4.     // 正确:使用clone()创建深拷贝
  5.     cv::Mat dst = src.clone();
  6.    
  7.     // 修改dst不会影响src
  8.     dst.setTo(cv::Scalar(0, 0, 0));
  9.     // src保持不变
  10.    
  11.     // 在循环外创建Mat对象,循环内重用
  12.     cv::Mat temp;
  13.     for (int i = 0; i < 100; ++i) {
  14.         temp = src.clone(); // 重用temp对象
  15.         // 处理temp...
  16.     }
  17. }
复制代码

内存释放最佳实践

1. 正确使用release()方法

Mat类的release()方法可以显式释放矩阵数据:
  1. cv::Mat img = cv::imread("image.jpg");
  2. // 使用img...
  3. // 显式释放内存
  4. img.release();
  5. // 或者通过赋值空Mat释放
  6. img = cv::Mat();
复制代码

需要注意的是,release()方法只释放矩阵数据,不释放矩阵头。而且,如果有其他Mat对象引用同一数据块,release()只会减少引用计数,不会立即释放内存。

2. 利用RAII模式

RAII(Resource Acquisition Is Initialization)是C++中管理资源的重要模式,可以自动管理Mat对象的内存:
  1. class ImageProcessor {
  2. private:
  3.     cv::Mat image;
  4.    
  5. public:
  6.     ImageProcessor(const std::string& imagePath) {
  7.         image = cv::imread(imagePath);
  8.     }
  9.    
  10.     ~ImageProcessor() {
  11.         if (!image.empty()) {
  12.             image.release();
  13.         }
  14.     }
  15.    
  16.     // 其他方法...
  17. };
  18. void processImage() {
  19.     ImageProcessor processor("image.jpg");
  20.     // 使用processor处理图像...
  21. } // processor离开作用域,自动调用析构函数释放内存
复制代码

3. 智能指针管理Mat

使用C++智能指针管理Mat对象的生命周期:
  1. void processImage() {
  2.     // 使用unique_ptr管理单个Mat
  3.     std::unique_ptr<cv::Mat> imgPtr = std::make_unique<cv::Mat>(cv::imread("image.jpg"));
  4.    
  5.     // 使用shared_ptr管理多个Mat
  6.     std::shared_ptr<cv::Mat> sharedImgPtr = std::make_shared<cv::Mat>(cv::imread("image.jpg"));
  7.    
  8.     // 使用imgPtr和sharedImgPtr...
  9. } // 智能指针离开作用域,自动释放内存
复制代码

4. 使用Mat的析构函数自动释放

Mat类的析构函数会自动检查引用计数,并在适当的时候释放内存:
  1. void foo() {
  2.     cv::Mat img = cv::imread("image.jpg");
  3.     // 使用img...
  4. } // img离开作用域,析构函数自动检查并释放内存
复制代码

这种方法是最简单、最安全的,适用于大多数情况。

内存泄漏检测工具和方法

1. Valgrind

Valgrind是一个强大的内存调试工具,可以检测内存泄漏、内存访问错误等问题:
  1. valgrind --leak-check=full --show-leak-kinds=all ./your_program
复制代码

2. Visual Studio内存诊断

在Visual Studio中,可以使用内置的内存诊断工具:
  1. #define _CRTDBG_MAP_ALLOC
  2. #include <stdlib.h>
  3. #include <crtdbg.h>
  4. int main() {
  5.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  6.    
  7.     // 你的代码...
  8.    
  9.     return 0;
  10. }
复制代码

3. 自定义内存跟踪

可以创建自定义的内存跟踪类来监控Mat对象的创建和销毁:
  1. class MatTracker {
  2. private:
  3.     std::map<void*, std::string> matMap;
  4.     std::mutex mutex;
  5.    
  6. public:
  7.     void track(cv::Mat& mat, const std::string& name) {
  8.         std::lock_guard<std::mutex> lock(mutex);
  9.         matMap[mat.data] = name;
  10.     }
  11.    
  12.     void untrack(cv::Mat& mat) {
  13.         std::lock_guard<std::mutex> lock(mutex);
  14.         matMap.erase(mat.data);
  15.     }
  16.    
  17.     void printTrackedMats() {
  18.         std::lock_guard<std::mutex> lock(mutex);
  19.         std::cout << "Tracked Mats:" << std::endl;
  20.         for (const auto& pair : matMap) {
  21.             std::cout << "  " << pair.second << " at " << pair.first << std::endl;
  22.         }
  23.     }
  24. };
  25. // 全局跟踪器
  26. MatTracker g_matTracker;
  27. // 跟踪Mat的宏
  28. #define TRACK_MAT(mat, name) g_matTracker.track(mat, name)
  29. #define UNTRACK_MAT(mat) g_matTracker.untrack(mat)
  30. void example() {
  31.     cv::Mat img = cv::imread("image.jpg");
  32.     TRACK_MAT(img, "example_img");
  33.    
  34.     // 使用img...
  35.    
  36.     UNTRACK_MAT(img);
  37.     img.release();
  38.    
  39.     g_matTracker.printTrackedMats(); // 检查是否有未释放的Mat
  40. }
复制代码

实战案例分析

案例1:视频处理中的内存泄漏

问题描述:在视频处理应用中,程序运行一段时间后崩溃,内存使用量持续增长。

问题代码:
  1. void processVideo(const std::string& videoPath) {
  2.     cv::VideoCapture cap(videoPath);
  3.     if (!cap.isOpened()) {
  4.         std::cerr << "Error opening video file" << std::endl;
  5.         return;
  6.     }
  7.    
  8.     cv::Mat frame;
  9.     while (cap.read(frame)) {
  10.         // 创建多个临时Mat对象
  11.         cv::Mat gray, blurred, edges;
  12.         
  13.         cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
  14.         cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);
  15.         cv::Canny(blurred, edges, 50, 150);
  16.         
  17.         // 显示结果
  18.         cv::imshow("Edges", edges);
  19.         if (cv::waitKey(30) >= 0) break;
  20.     }
  21.    
  22.     cap.release();
  23.     cv::destroyAllWindows();
  24. }
复制代码

问题分析:虽然代码看起来没有明显问题,但在循环中创建了多个临时Mat对象(gray, blurred, edges),虽然它们在每次循环结束时都会离开作用域,但在某些情况下(如异常或提前退出),可能不会正确释放内存。

解决方案:
  1. void processVideo(const std::string& videoPath) {
  2.     cv::VideoCapture cap(videoPath);
  3.     if (!cap.isOpened()) {
  4.         std::cerr << "Error opening video file" << std::endl;
  5.         return;
  6.     }
  7.    
  8.     // 在循环外创建Mat对象,重用它们
  9.     cv::Mat frame, gray, blurred, edges;
  10.    
  11.     try {
  12.         while (cap.read(frame)) {
  13.             // 重用Mat对象
  14.             cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
  15.             cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);
  16.             cv::Canny(blurred, edges, 50, 150);
  17.             
  18.             // 显示结果
  19.             cv::imshow("Edges", edges);
  20.             if (cv::waitKey(30) >= 0) break;
  21.         }
  22.     } catch (const std::exception& e) {
  23.         std::cerr << "Exception: " << e.what() << std::endl;
  24.     }
  25.    
  26.     // 显式释放资源
  27.     frame.release();
  28.     gray.release();
  29.     blurred.release();
  30.     edges.release();
  31.     cap.release();
  32.     cv::destroyAllWindows();
  33. }
复制代码

案例2:多线程环境中的Mat共享

问题描述:在多线程图像处理应用中,多个线程需要访问同一图像数据,但频繁的内存分配和释放导致性能下降。

问题代码:
  1. std::vector<cv::Mat> imageQueue;
  2. std::mutex queueMutex;
  3. void producerThread(const std::vector<std::string>& imagePaths) {
  4.     for (const auto& path : imagePaths) {
  5.         cv::Mat img = cv::imread(path);
  6.         if (!img.empty()) {
  7.             std::lock_guard<std::mutex> lock(queueMutex);
  8.             imageQueue.push_back(img.clone()); // 深拷贝,性能低
  9.         }
  10.     }
  11. }
  12. void consumerThread() {
  13.     while (true) {
  14.         cv::Mat img;
  15.         {
  16.             std::lock_guard<std::mutex> lock(queueMutex);
  17.             if (!imageQueue.empty()) {
  18.                 img = imageQueue.back().clone(); // 再次深拷贝
  19.                 imageQueue.pop_back();
  20.             }
  21.         }
  22.         
  23.         if (!img.empty()) {
  24.             // 处理图像...
  25.         } else {
  26.             std::this_thread::sleep_for(std::chrono::milliseconds(10));
  27.         }
  28.     }
  29. }
复制代码

问题分析:代码中使用了多次深拷贝(clone()),导致不必要的内存分配和复制,降低了性能。

解决方案:
  1. // 使用共享指针避免深拷贝
  2. std::vector<std::shared_ptr<cv::Mat>> imageQueue;
  3. std::mutex queueMutex;
  4. void producerThread(const std::vector<std::string>& imagePaths) {
  5.     for (const auto& path : imagePaths) {
  6.         auto imgPtr = std::make_shared<cv::Mat>(cv::imread(path));
  7.         if (!imgPtr->empty()) {
  8.             std::lock_guard<std::mutex> lock(queueMutex);
  9.             imageQueue.push_back(imgPtr); // 共享指针,避免深拷贝
  10.         }
  11.     }
  12. }
  13. void consumerThread() {
  14.     while (true) {
  15.         std::shared_ptr<cv::Mat> imgPtr;
  16.         {
  17.             std::lock_guard<std::mutex> lock(queueMutex);
  18.             if (!imageQueue.empty()) {
  19.                 imgPtr = imageQueue.back(); // 共享指针,引用计数增加
  20.                 imageQueue.pop_back();
  21.             }
  22.         }
  23.         
  24.         if (imgPtr && !imgPtr->empty()) {
  25.             // 处理图像,使用 *imgPtr 访问Mat对象
  26.             // 如果需要修改图像,且不想影响原始数据,可以创建副本
  27.             cv::Mat processedImg = imgPtr->clone();
  28.             // 处理processedImg...
  29.         } else {
  30.             std::this_thread::sleep_for(std::chrono::milliseconds(10));
  31.         }
  32.     }
  33. }
复制代码

案例3:类成员Mat导致的内存泄漏

问题描述:在一个图像处理类中,频繁加载和处理图像导致内存使用量持续增长。

问题代码:
  1. class ImageProcessor {
  2. private:
  3.     cv::Mat originalImage;
  4.     cv::Mat processedImage;
  5.    
  6. public:
  7.     void loadImage(const std::string& path) {
  8.         originalImage = cv::imread(path); // 替换旧图像
  9.     }
  10.    
  11.     void processImage() {
  12.         if (originalImage.empty()) return;
  13.         
  14.         // 创建多个临时Mat对象
  15.         cv::Mat gray, blurred, edges;
  16.         cv::cvtColor(originalImage, gray, cv::COLOR_BGR2GRAY);
  17.         cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);
  18.         cv::Canny(blurred, edges, 50, 150);
  19.         
  20.         processedImage = edges; // 赋值操作,共享数据
  21.     }
  22.    
  23.     cv::Mat getProcessedImage() const {
  24.         return processedImage; // 返回副本
  25.     }
  26. };
复制代码

问题分析:虽然代码看起来没有明显问题,但在频繁调用loadImage和processImage时,可能会导致内存碎片和内存泄漏。特别是在某些情况下,processedImage可能引用了临时对象(如edges),而这些临时对象可能已经被销毁。

解决方案:
  1. class ImageProcessor {
  2. private:
  3.     cv::Mat originalImage;
  4.     cv::Mat processedImage;
  5.    
  6. public:
  7.     ImageProcessor() {}
  8.    
  9.     ~ImageProcessor() {
  10.         releaseImages();
  11.     }
  12.    
  13.     void loadImage(const std::string& path) {
  14.         // 显式释放旧图像
  15.         releaseImages();
  16.         
  17.         originalImage = cv::imread(path);
  18.     }
  19.    
  20.     void processImage() {
  21.         if (originalImage.empty()) return;
  22.         
  23.         // 显式释放旧的处理结果
  24.         processedImage.release();
  25.         
  26.         // 使用局部变量处理图像
  27.         cv::Mat gray, blurred, edges;
  28.         cv::cvtColor(originalImage, gray, cv::COLOR_BGR2GRAY);
  29.         cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);
  30.         cv::Canny(blurred, edges, 50, 150);
  31.         
  32.         // 深拷贝结果,避免引用临时对象
  33.         processedImage = edges.clone();
  34.     }
  35.    
  36.     cv::Mat getProcessedImage() const {
  37.         // 返回深拷贝,避免外部修改内部数据
  38.         return processedImage.empty() ? cv::Mat() : processedImage.clone();
  39.     }
  40.    
  41.     void releaseImages() {
  42.         originalImage.release();
  43.         processedImage.release();
  44.     }
  45. };
复制代码

总结

OpenCV的Mat类提供了强大的图像处理功能,但正确的内存管理对于编写稳定、高效的程序至关重要。本文详细介绍了Mat的内存管理机制,分析了常见的内存泄漏场景,并提供了实用的解决方案和最佳实践。

关键要点包括:

1. 理解Mat的引用计数机制,避免不必要的深拷贝。
2. 在循环中重用Mat对象,减少内存分配和释放的频率。
3. 正确处理函数间的Mat传递,优先使用引用传递或OpenCV的InputArray/OutputArray。
4. 在类中使用Mat作为成员变量时,注意对象的生命周期,必要时显式释放内存。
5. 避免直接使用Mat指针,优先使用容器或智能指针管理Mat对象。
6. 使用RAII模式和智能指针自动管理Mat对象的生命周期。
7. 利用内存检测工具定期检查程序中的内存泄漏问题。

通过遵循这些最佳实践,开发者可以有效避免OpenCV程序中的内存泄漏问题,提高程序的稳定性和性能。记住,良好的内存管理习惯是编写高质量OpenCV应用程序的基础。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

手机版|联系我们|小黑屋|TG频道|RSS |网站地图

Powered by Pixtech

© 2025-2026 Pixtech Team.

>