当前位置: 首页 > article >正文

C++ 内存泄漏检测器设计

文章目录

  • 1. C++中的动态内存分配
  • 2. 什么是内存泄漏
  • 3. 内存泄漏的代码案例
  • 4. 内存泄漏检查器的设计
    • 模块1:位置信息捕获:
    • 模块2:内存分配跟踪:
    • 模块3:内存释放跟踪:
    • 模块4:泄漏记录存储:
    • 模块5:报告生成:
  • 5. 测试案例


在这里插入图片描述


1. C++中的动态内存分配

动态内存分配不同于固定大小的静态数组,通过 new 和 delete让我们可以根据需要随时申请和释放内存。

先来看段代码:

#include <iostream>
using namespace std;int main() {// 动态分配单个整型变量int* pInt = new int;*pInt = 20;cout << "动态分配的整数数值为: " << *pInt << endl;// 释放内存delete pInt;// 动态分配数组int arraySize;cout << "请指定数组的大小: ";cin >> arraySize;int* dynamicArray = new int[arraySize];for (int i = 0; i < arraySize; i++) {dynamicArray[i] = i * 3;}cout << "数组中的元素为: ";for (int i = 0; i < arraySize; i++) {cout << dynamicArray[i] << " ";}cout << endl;// 释放数组内存delete[] dynamicArray;return 0;
}

上面的代码,做了如下事情:

动态分配单个整型变量:

  1. 内存分配:new int在堆上分配 int 类型的内存。
  2. 指针操作:通过*pInt解引用赋值和读取。
  3. 内存释放:使用delete释放单个对象内存。

动态分配数组:

  1. 内存分配:new int[arraySize]分配连续内存块。
  2. 指针类型:dynamicArray指向数组首元素(类型为int*)。
  3. 数组释放:使用delete[]释放数组内存。

注意事项:无论是单个变量还是数组,动态分配的内存都需要通过 delete 或 delete[] 进行释放。

2. 什么是内存泄漏

内存泄漏是指程序在运行过程中申请了内存空间却未及时释放,导致随着程序运行时间增长,占用的内存持续累积,最终可能耗尽系统可用资源。在 C++ 编程中,避免内存泄漏需牢记以下要点:

  1. 内存释放的配对原则:
    每次通过 new 分配的单个内存对象,必须使用 delete 进行释放;对于通过 new[] 动态分配的数组内存,则需用 delete[] 释放。
  2. 系统不会自动回收动态内存:
    与栈内存不同,堆内存的释放完全依赖开发者手动操作。若忘记释放已申请的动态内存,系统无法自动清理这些 “闲置” 内存,它们会一直驻留在内存中,形成内存泄漏。所以在动态内存使用完毕后,应立即执行释放操作。

3. 内存泄漏的代码案例

1. 基础堆内存未释放(Basic Heap Leak):

new分配的内存未通过delete释放。

int* p = new int; // 未释放

2. 数组未正确释放(Array Deallocation Mismatch):

new[]分配的数组必须用delete[]释放。若使用delete而非delete[],仅释放首元素内存,其余元素内存泄漏。

int* arr = new int[10];// delete arr;        // 错误写法// 正确应使用 delete[] arr;

3. 异常路径未释放(Exception Safety Issue)

异常抛出后,delete语句被跳过,内存未释放。

int* data = new int;
throw std::runtime_error("Oops!"); // 异常导致delete跳过
delete data; // 永远不会执行

4. 类成员未释放(Class Member Leak)

动态分配的成员变量buf未在析构函数中释放。当对象销毁时,buf指向的内存仍被占用。

class LeakyClass {
public:LeakyClass() : buf(new char[1024]) {}~LeakyClass() {}  // 析构函数未释放buf
private:char* buf;
};

5. 容器指针未清理(Container of Pointers)

vector存储的是原始指针,容器销毁时不会自动释放指针指向的内存。

std::vector<int*> vec;
for (int i = 0; i < 5; ++i) {vec.push_back(new int(i)); // 未释放元素
}

4. 内存泄漏检查器的设计

原理:通过重载 new/new[] 和 delete/delete[] 运算符,在内存分配/释放时插入跟踪逻辑,在内存分配时:记录内存地址、大小、分配位置(FILELINE),在内存释放时:从跟踪表中移除记录。

模块1:位置信息捕获:

通过预处理器宏替换,在每次内存分配时自动捕获源代码位置信息:文件名和行号。

关键技术点:

  1. 利用__FILE__和__LINE__预定义宏获取当前位置。
  2. 通过宏替换将普通new操作转换为带位置信息的版本。
  3. 避免在实现文件中应用宏替换:防止递归定义。
// mem_leak_detector.hpp
#ifndef MEM_LEAK_DETECTOR_IMPLEMENTATION
// 关键替换:所有new操作被转换为带位置信息的版本
#define new new(__FILE__, __LINE__)
#endif// 位置感知的内存分配运算符声明
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);

模块2:内存分配跟踪:

重载全局内存分配函数,在分配时记录内存信息。

关键技术点:

  1. 重载operator new和operator new[]捕获分配请求。
  2. 使用malloc进行实际内存分配。
  3. 分配成功后记录指针、大小和位置信息。
  4. 处理分配失败情况返回nullptr。
// mem_leak_detector.cpp
// 重载的全局new运算符
void* operator new(size_t size, const char* file, int line) {void* p = malloc(size);  // 实际内存分配if (p) {// 记录分配信息:指针、大小、文件名、行号MemLeakDetector::track(p, size, file, line);}return p;
}// 数组版本转发给普通new
void* operator new[](size_t size, const char* file, int line) {return operator new(size, file, line);
}// 跟踪函数实现
void MemLeakDetector::track(void* p, size_t size, const char* file, int line) {char* file_copy = strdup(file);  // 复制文件名(确保长期有效)allocations[p] = MemAllocRecord{p, size, file_copy, line};
}

模块3:内存释放跟踪:

重载全局内存释放函数,在释放时移除跟踪记录。

关键技术点:

  1. 重载operator delete和operator delete[]。
  2. 释放前从跟踪表中移除记录。
  3. 使用free进行实际内存释放。
// mem_leak_detector.cpp
// 重载的全局delete运算符
void operator delete(void* p) noexcept {MemLeakDetector::untrack(p);  // 从跟踪表中移除free(p);  // 实际内存释放
}// 数组版本转发给普通delete
void operator delete[](void* p) noexcept {operator delete(p);
}// 停止跟踪函数实现
void MemLeakDetector::untrack(void* p) {auto it = allocations.find(p);if (it != allocations.end()) {free((void*)it->second.file);  // 释放复制的文件名allocations.erase(it);  // 从映射表移除}
}

模块4:泄漏记录存储:

使用全局数据结构存储所有未释放的内存分配记录。

关键技术点:

  1. 静态std::map存储分配记录—键:内存地址,值:分配信息。
  2. 使用strdup复制文件名,确保长期有效性。
  3. 在释放时清理复制的文件名。
// mem_leak_detector.hpp
// 内存分配记录结构
struct MemAllocRecord {void* ptr;          // 内存地址size_t size;        // 分配大小const char* file;   // 分配位置文件名int line;           // 分配位置行号
};// 静态存储定义
class MemLeakDetector {private:static std::map<void*, MemAllocRecord> allocations;  // 未释放内存记录表// ...
};

模块5:报告生成:

程序退出时分析未释放记录,生成详细泄漏报告。

关键技术点:

  1. 通过atexit注册报告函数。
  2. 遍历所有未释放记录。
  3. 计算总泄漏字节数。
  4. 分类显示泄漏位置信息。
  5. 区分"无泄漏"和"有泄漏"情况。
// mem_leak_detector.cpp
// 生成泄漏报告:程序退出时自动调用
void MemLeakDetector::report() {if (allocations.empty()) {std::cout << "\n[SUCCESS] No memory leaks detected\n";} else {std::cout << "\n[MEMORY LEAKS] " << allocations.size() << " leaks found:\n";size_t total = 0;// 遍历所有未释放的记录for (const auto& entry : allocations) {const MemAllocRecord& record = entry.second;std::cout << "  Leak at " << record.ptr << " (" << record.size << " bytes)"<< " allocated in " << record.file<< ":" << record.line << "\n";total += record.size;  // 累计泄漏字节数}std::cout << "Total leaked: " << total << " bytes\n";}
}
// 初始化宏注册报告函数
#define MEM_LEAK_DETECTOR_INIT() \std::atexit(MemLeakDetector::report)

5. 测试案例

测试案例放在main.cpp文件中,内存泄漏检测文件由mem_leak_detector.cpp和mem_leak_detector.hpp组成,我使用的lab环境为 Ubuntu 系统。

执行以下命令看到结果:

g++ -std=c++11 -g mem_leak_detector.cpp main.cpp -o memtest
./memtest

在这里插入图片描述

main.cpp

#include <vector>
#include <stdexcept>
#include "mem_leak_detector.hpp"  // 引入内存泄漏检测器头文件// 基础内存泄漏示例:分配单个int未释放
void basic_leak() {int* p = new int;  // 分配内存 (通过重载的new记录位置)
}// 数组内存泄漏示例:分配int数组未释放
void array_leak() {int* arr = new int[10];  // 分配数组 (通过重载的new[]记录)
}// 异常导致的内存泄漏:分配后抛出异常跳过delete
void exception_leak() {int* data = new int; throw std::runtime_error("Oops!");  // 抛出异常delete data;  // 此句不会执行
}// 类内泄漏示例:析构函数未释放成员指针
class LeakyClass {
public:LeakyClass() : buf(new char[1024]) {}  // 分配内存~LeakyClass() {}  // 析构函数未释放buf → 泄漏
private:char* buf;
};// 容器内存泄漏示例:vector存储指针未释放
void container_leak() {std::vector<int*> vec;for (int i = 0; i < 5; ++i) {vec.push_back(new int(i));  // 5次分配}  // vector销毁时不会自动释放指针 → 5处泄漏
}int main() {MEM_LEAK_DETECTOR_INIT();  // 注册退出时报告泄漏basic_leak();        // 产生1处泄漏array_leak();        // 产生1处泄漏 (数组)try { exception_leak();  // 抛出异常导致1处泄漏} catch (...) {}       // 捕获异常但不处理泄漏LeakyClass* cls = new LeakyClass();  // 类内泄漏 + 对象本身泄漏 → 共2处container_leak();     // 产生5处泄漏// 注意:未释放cls指针 → 额外泄漏LeakyClass对象return 0;
}  // 程序退出时自动调用report()

mem_leak_detector.hpp

#pragma once
#ifndef MEM_LEAK_DETECTOR_HPP
#define MEM_LEAK_DETECTOR_HPP#include <map>
#include <string>
#include <iostream>
#include <cstdlib>// 内存分配记录结构体
struct MemAllocRecord {void* ptr;          // 分配的内存地址size_t size;        // 分配的字节数const char* file;   // 分配发生的源文件名int line;           // 分配发生的代码行号
};class MemLeakDetector {
public:// 跟踪内存分配(由重载的new调用)static void track(void* p, size_t size, const char* file, int line);// 停止跟踪内存(由重载的delete调用)static void untrack(void* p);// 生成泄漏报告(程序退出时调用)static void report();
private:static std::map<void*, MemAllocRecord> allocations;  // 未释放内存记录表
};// 声明带位置信息的全局运算符重载
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
void operator delete(void* p) noexcept;
void operator delete[](void* p) noexcept;// 初始化宏:注册报告函数到atexit
#define MEM_LEAK_DETECTOR_INIT() \std::atexit(MemLeakDetector::report)// 在非实现文件中重定义new宏(捕获分配位置)
#ifndef MEM_LEAK_DETECTOR_IMPLEMENTATION
#define new new(__FILE__, __LINE__)  // 替换所有new为带位置信息的版本
#endif#endif

mem_leak_detector.cpp

#define MEM_LEAK_DETECTOR_IMPLEMENTATION  // 启用实现模式
#include "mem_leak_detector.hpp"
#include <cstring>
#include <cstdlib>
#include <iostream>// 静态成员初始化:存储所有未释放的内存记录
std::map<void*, MemAllocRecord> MemLeakDetector::allocations;// 跟踪内存分配:记录指针、大小、文件名和行号
void MemLeakDetector::track(void* p, size_t size, const char* file, int line) {char* file_copy = strdup(file);  // 复制文件名字符串allocations[p] = MemAllocRecord{p, size, file_copy, line};  // 存入映射表
}// 停止跟踪:内存释放时从映射表移除记录
void MemLeakDetector::untrack(void* p) {auto it = allocations.find(p);if (it != allocations.end()) {free((void*)it->second.file);  // 释放复制的文件名内存allocations.erase(it);         // 移除记录}
}// 生成泄漏报告:程序退出时自动调用
void MemLeakDetector::report() {if (allocations.empty()) {std::cout << "\n[SUCCESS] No memory leaks detected\n";} else {std::cout << "\n[MEMORY LEAKS] " << allocations.size() << " leaks found:\n";size_t total = 0;// 遍历所有未释放的记录for (const auto& entry : allocations) {const MemAllocRecord& record = entry.second;std::cout << "  Leak at " << record.ptr << " (" << record.size << " bytes)"<< " allocated in " << record.file<< ":" << record.line << "\n";total += record.size;  // 累计泄漏字节数}std::cout << "Total leaked: " << total << " bytes\n";}
}// 重载全局new运算符:捕获分配位置信息
void* operator new(size_t size, const char* file, int line) {void* p = malloc(size);        // 实际内存分配if (p) {// 记录分配信息:指针、大小、文件名、行号MemLeakDetector::track(p, size, file, line);}return p;
}// 重载全局new[]运算符:转发给带位置信息的new
void* operator new[](size_t size, const char* file, int line) {return operator new(size, file, line);
}// 重载全局delete运算符:释放内存并停止跟踪
void operator delete(void* p) noexcept {MemLeakDetector::untrack(p);  // 从跟踪表中移除free(p);                      // 实际释放内存
}// 重载全局delete[]运算符:转发给delete
void operator delete[](void* p) noexcept {operator delete(p);
}

相关文章:

C++ 内存泄漏检测器设计

文章目录 1. C中的动态内存分配2. 什么是内存泄漏3. 内存泄漏的代码案例4. 内存泄漏检查器的设计模块1&#xff1a;位置信息捕获&#xff1a;模块2&#xff1a;内存分配跟踪&#xff1a;模块3&#xff1a;内存释放跟踪&#xff1a;模块4&#xff1a;泄漏记录存储&#xff1a;模…...

在 Linux 上安装 Nmap 工具

&#x1f4e6; 在 Linux 上安装 Nmap 工具指南 Nmap&#xff08;Network Mapper&#xff09;是功能强大的网络扫描工具&#xff0c;以下是各种 Linux 发行版的安装方法&#xff1a; &#x1f9e9; 通用安装方法 1. 使用包管理器安装&#xff08;推荐&#xff09; # Debian/…...

从零打造AI面试系统全栈开发

&#x1f916; AI面试系统开发完整教程 &#x1f4cb; 项目概述 本教程将带你从零开始构建一个完整的AI面试系统&#xff0c;包含前端、后端、AI集成和部署的全流程。 源码地址 技术栈 前端: React TypeScript Vite Vaadin Components后端: Spring Boot Spring Securi…...

破局与进阶:ueBIM 在国产 BIM 赛道的差距认知与创新实践

作为国产BIM领域的探索者&#xff0c;斯维尔ueBIM自诞生以来始终以追赶国际头部技术为目标&#xff0c;但不可否认的是&#xff0c;在核心功能覆盖、行业生态成熟度以及全球市场占有率等方面&#xff0c;我们与Autodesk Revit、Bentley Systems等国际巨头仍存在显著差距。这种差…...

分布式流处理与消息传递——向量时钟 (Vector Clocks) 算法详解

Java 实现向量时钟 (Vector Clocks) 算法详解 一、向量时钟核心原理 #mermaid-svg-JcZ1GT0r1ZNSy6W7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JcZ1GT0r1ZNSy6W7 .error-icon{fill:#552222;}#mermaid-svg-JcZ…...

20250603在荣品的PRO-RK3566开发板的Android13下的命令行查看RK3566的温度

20250603在荣品的PRO-RK3566开发板的Android13下的命令行查看RK3566的温度 2025/6/3 11:58 RK3566的cpu运行效率 top rk3566_t:/ # rk3566_t:/ # rk3566_t:/ # cd /sys/class/thermal/ rk3566_t:/sys/class/thermal # ls -l rk3566_t:/sys/class/thermal # cd thermal_zone0/ r…...

帝可得 - 设备管理

一. 需求说明 设备管理主要涉及到三个功能模块&#xff0c;业务流程如下&#xff1a; 新增设备类型: 允许管理员定义新的售货机型号&#xff0c;包括其规格和容量。 新增设备: 在新的设备类型定义后&#xff0c;系统应允许添加新的售货机实例&#xff0c;并将它们分配到特定的…...

FTXUI配置

对于 FTXUI 的安装与配置, 官方已经给出了三种方案. 第一种: 使用 FetchContent 远程拉取第二种: 在你本地安装 FTXUI 库, 然后通过 find_package 使用第三种: 使用 Git 子模块 FetchContent 无需手动下载安装 FTXUI, 通过 CMake 自动从 GitHub 拉取并编译依赖 include(Fet…...

Caliper压力测试

目前FISCO BCOS适配的Caliper版本为0.2.0&#xff0c;请在部署Caliper运行环境时确保Caliper的版本为0.2.0&#xff0c;如在部署或使用过程中遇到任何问题&#xff0c;请优先参考 https://github.com/FISCO-BCOS/FISCO-BCOS/issues/1248 中的解决方案进行排查。 1. 环境要求 …...

【iOS安全】使用LLDB调试iOS App | LLDB基本架构 | LLDB安装和配置

LLDB基本架构 参考&#xff1a; https://crifan.github.io/ios_re_dynamic_debug/website/debug_code/lldb_debugserver.html https://book.crifan.org/books/ios_re_debug_debugserver_lldb/website/ LLDB安装和配置 1. 让iPhone中出现/Developer/usr/bin/debugserver 最初…...

一、核心概念深入解析

一、核心概念深入解析 1. shared_ptr 的线程安全性澄清 引用计数是原子操作&#xff1a;shared_ptr 的引用计数&#xff08;use_count&#xff09;在多线程中递增 / 递减是安全的&#xff08;原子操作&#xff09;&#xff0c;但对象本身的读写需额外同步&#xff08;如 std:…...

python直方图

在Python中&#xff0c;绘制直方图&#xff08;Histogram&#xff09;是一项非常常见的任务&#xff0c;通常用于数据可视化&#xff0c;以展示数据的分布情况。Python中有多种库可以绘制直方图&#xff0c;其中最常用的两个库是Matplotlib和Seaborn。此外&#xff0c;Pandas库…...

[特殊字符] Unity 性能优化终极指南 — Text / TextMeshPro 组件篇

UGUI Text组件的不当使用及其性能瓶颈与优化 在Unity UGUI系统中&#xff0c;Text 组件&#xff08;或其升级版 TextMeshPro&#xff09;是显示文本信息的核心元素。然而&#xff0c;如果不当使用&#xff0c;它极易成为UI性能瓶颈的罪魁祸首&#xff0c;尤其是在预制体、属性…...

Idea 配置 Maven 环境

下载 Maven 官网&#xff1a;https://maven.apache.org/index.html 点击左侧 Downloads&#xff0c;然后选择 Files 中的 zip 包下载&#xff08;下载慢可以使用迅雷&#xff09; 配置 Maven 将压缩包解压&#xff0c;比如我解压后放到了 D:\developer\environment\apache-…...

git clone报错:SSL certificate problem: unable to get local issuer certificate

上述报错的完整信息是&#xff1a; Cloning into test... fatal: unable to access https://github.com/xxxx/xxxx.git/: SSL certificate problem: unable to get local issuer certificate 该报错表示 Git 在使用 HTTPS 协议克隆仓库时&#xff0c;无法验证 GitHub 的 SSL …...

Kafka 如何保证不重复消费

在消息队列的使用场景中&#xff0c;避免消息重复消费是保障数据准确性和业务逻辑正确性的关键。对于 Kafka 而言&#xff0c;保证不重复消费并非单一机制就能实现&#xff0c;而是需要从生产者、消费者以及业务层等多个维度协同配合。接下来&#xff0c;我们将结合图文详细解析…...

SpringBoot整合MyBatis完整实践指南

在Java企业级应用开发中&#xff0c;SpringBoot和MyBatis的组合已经成为主流的技术选型方案之一。本文将详细介绍如何从零开始搭建一个基于SpringBoot和MyBatis的项目&#xff0c;包括环境配置、数据库设计、实体类创建、Mapper接口编写以及实际应用等完整流程。 一、环境准备…...

RNN结构扩展与改进:从简单循环网络到时间间隔网络的技术演进

本文系统介绍 RNN 结构的常见扩展与改进方案。涵盖 简单循环神经网络&#xff08;SRN&#xff09;、双向循环神经网络&#xff08;BRNN&#xff09;、深度循环神经网络&#xff08;Deep RNN&#xff09; 等多种变体&#xff0c;解析其核心架构、技术特点及应用场景&#xff0c;…...

docker中,容器时间和宿机主机时间不一致问题

win11下的docker中有个mysql。今天发现插入数据的时间不正确。后来发现原来是docker容器中的时间不正确。于是尝试了各种修改&#xff0c;什么run -e TZ"${tzutil /g}"&#xff0c;TZ"Asia/Shanghai"&#xff0c;还有初始化时带--mysqld一类的&#xff0c;…...

Unity Shader编程】之高级纹理

一&#xff0c;立方体纹理 Cubemap 用途 用途说明反射贴图表面镜面高光或金属反射环境光采样模拟环境对物体的影响天空盒背景使用六张图拼接场景背景全景投影做360度相机渲染、投影等 二&#xff0c;创建立方体纹理 在 Unity 中创建和保存一个 立方体纹理&#xff08;Cubema…...

类 Excel 数据填报

类 Excel 填报模式&#xff0c;满足用户 Excel 使用习惯 数据填报&#xff0c;可作为独立的功能模块&#xff0c;用于管理业务流程、汇总采集数据&#xff0c;以及开发各类数据报送系统&#xff0c;因此&#xff0c;对于报表工具而言&#xff0c;其典型场景之一就是利用报表模…...

vscode调试stm32,Cortex Debug的配置文件lanuch.json如何写,日志

https://blog.csdn.net/jiladahe1997/article/details/122046665 https://discuss.em-ide.com/blog/67-cortex-debug 第一版 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?li…...

Office文档图片批量导出工具

软件介绍 本文介绍一款专业的Office文档图片批量导出工具。 软件特点 这款软件能够批量导出Word、Excel和PPT中的图片&#xff0c;采用绿色单文件设计&#xff0c;体积小巧仅344KB。 基本操作流程 使用方法十分简单&#xff1a;直接将Word、Excel或PPT文件拖入软件&#xf…...

【iOS】ARC 与 Autorelease

ARC 与 Autorelease 文章目录 ARC 与 Autorelease前言何为ARC内存管理考虑方式自己生成的对象,自己持有非自己生成的对象,自己也可以持有不再需要自己持有的对象时释放非自己持有的对象无法释放 ARC的具体实现编译期和运行期ARC做的事情ARC实现: __autoreleasing 与 Autoreleas…...

人工智能在智能零售中的创新应用与未来趋势

随着电子商务的蓬勃发展和消费者需求的不断变化&#xff0c;零售行业正面临着前所未有的挑战和机遇。智能零售作为零售行业的重要发展方向&#xff0c;通过引入人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;、大数据和云计算等前沿技术&#xff0c;正…...

业务材料——半导体行业MES系统核心功能工业协议AI赋能

一、前置概念 半导体行业 半导体行业主要生产基于半导体材料&#xff08;如硅、锗、化合物半导体等&#xff09;的电子元器件及相关产品&#xff0c;广泛应用于计算、通信、能源、医疗等领域。 MES系统 MES系统&#xff08;Manufacturing Execution System&#xff0c;制造…...

docker部署命令行 — 启动一个 MySQL 数据库服务 并且把它的数据存储挂载到卷(volume)里

挂载卷的配置写法&#xff1a; version: "3" services:db:image: mysqlvolumes:- mysql_data:/var/lib/mysqlvolumes:mysql_data:这段 docker-compose.yml 配置非常典型&#xff0c;是用来启动一个 MySQL 数据库服务 并且把它的数据存储挂载到卷&#xff08;volume&…...

铁电液晶破局 VR/AR:10000PPI 重构元宇宙显示体验

一、VR/AR 沉浸感困境&#xff1a;传统显示技术的天花板在哪&#xff1f; &#xff08;一&#xff09;纱窗效应与眩晕感&#xff1a;近眼显示的双重枷锁 当用户戴上 VR 头显&#xff0c;眼前像素网格形成的 “纱窗效应” 瞬间打破沉浸感。传统液晶 500-600PPI 的像素密度&…...

2025年微信小程序开发:AR/VR与电商的最新案例

引言 微信小程序自2017年推出以来&#xff0c;已成为中国移动互联网生态的核心组成部分。根据最新数据&#xff0c;截至2025年&#xff0c;微信小程序的日活跃用户超过4.5亿&#xff0c;总数超过430万&#xff0c;覆盖电商、社交、线下服务等多个领域&#xff08;WeChat Mini …...

从零开始,学会上传,更新,维护github仓库

以下是一份从头到尾、覆盖安装、配置、创建仓库、上传项目到 GitHub 的完整教程。全程使用通用示例&#xff0c;不包含任何具体的仓库链接&#xff0c;仅供参考。 一、准备工作 1. 注册 GitHub 账号 打开浏览器&#xff0c;访问 GitHub 官网&#xff08;输入 “GitHub” 即可找…...