news 2026/4/28 19:00:20

C++ new/delete 极简笔记:动态内存管理核心用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ new/delete 极简笔记:动态内存管理核心用法

动态内存分配基础

new运算符用于在堆内存中分配指定类型的内存空间,返回指向该内存的指针。基本语法为指针 = new 类型,例如:

int* ptr = new int; // 分配一个整型内存

delete运算符释放由new分配的内存,防止内存泄漏。语法为delete 指针

delete ptr; // 释放内存 ptr = nullptr; // 避免悬空指针

数组动态分配

使用new[]分配数组,delete[]释放数组内存。语法差异必须严格匹配:

int* arr = new int[10]; // 分配10个整型元素的数组 delete[] arr; // 释放数组内存

初始化动态内存

分配时可直接初始化:

int* val = new int(42); // 分配并初始化为42 int* arr_init = new int[5]{1, 2, 3, 4, 5}; // C++11起支持的列表初始化

常见错误与规范

内存泄漏:未调用delete释放已分配的内存。 悬空指针:释放后未置空指针,建议释放后立即设为nullptr。 类型不匹配:new[]必须对应delete[],反之亦然。

现代C++替代方案

优先使用智能指针(如std::unique_ptr)自动管理内存:

#include <memory> std::unique_ptr<int> smartPtr(new int(10)); // 自动释放内存

对于数组,C++14起可用make_unique

auto arrSmart = std::make_unique<int[]>(10); // 动态数组智能指针

动态内存分配基础

new运算符用于在堆内存中分配指定类型的内存空间,返回指向该内存的指针。基本语法为指针 = new 类型,例如:

int* ptr = new int; // 分配一个整型内存

delete运算符释放由new分配的内存,防止内存泄漏。语法为delete 指针

delete ptr; // 释放内存 ptr = nullptr; // 避免悬空指针

数组动态分配

使用new[]分配数组,delete[]释放数组内存。语法差异必须严格匹配:

int* arr = new int[10]; // 分配10个整型元素的数组 delete[] arr; // 释放数组内存

初始化动态内存

分配时可直接初始化:

int* val = new int(42); // 分配并初始化为42 int* arr_init = new int[5]{1, 2, 3, 4, 5}; // C++11起支持的列表初始化

常见错误与规范

内存泄漏:未调用delete释放已分配的内存。 悬空指针:释放后未置空指针,建议释放后立即设为nullptr。 类型不匹配:new[]必须对应delete[],反之亦然。

现代C++替代方案

优先使用智能指针(如std::unique_ptr)自动管理内存:

#include <memory> std::unique_ptr<int> smartPtr(new int(10)); // 自动释放内存

对于数组,C++14起可用make_unique

auto arrSmart = std::make_unique<int[]>(10); // 动态数组智能指针

动态内存分配基础

new运算符用于在堆内存中分配指定类型的内存空间,返回指向该内存的指针。基本语法为指针 = new 类型,例如:

int* ptr = new int; // 分配一个整型内存

delete运算符释放由new分配的内存,防止内存泄漏。语法为delete 指针

delete ptr; // 释放内存 ptr = nullptr; // 避免悬空指针

数组动态分配

使用new[]分配数组,delete[]释放数组内存。语法差异必须严格匹配:

int* arr = new int[10]; // 分配10个整型元素的数组 delete[] arr; // 释放数组内存

初始化动态内存

分配时可直接初始化:

int* val = new int(42); // 分配并初始化为42 int* arr_init = new int[5]{1, 2, 3, 4, 5}; // C++11起支持的列表初始化

常见错误与规范

内存泄漏:未调用delete释放已分配的内存。 悬空指针:释放后未置空指针,建议释放后立即设为nullptr。 类型不匹配:new[]必须对应delete[],反之亦然。

代码实现:Tomcat风格的类加载器

/** * 模拟Tomcat的Web应用类加载器 * 打破双亲委派:先自己加载,找不到再委托给父加载器 */ public class WebAppClassLoader extends ClassLoader { private String classPath; // 类加载路径 private Map<String, Class<?>> loadedClasses = new HashMap<>(); public WebAppClassLoader(String classPath, ClassLoader parent) { super(parent); this.classPath = classPath; } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 1. 检查类是否已被加载 Class<?> clazz = findLoadedClass(name); if (clazz != null) { return clazz; } // 2. 重要:如果是Java核心类,还是交给上级(安全第一!) if (name.startsWith("java.")) { try { clazz = getParent().loadClass(name); if (clazz != null) { return clazz; } } catch (ClassNotFoundException e) { // 忽略,继续向下执行 } } try { // 3. 打破双亲委派的关键:先自己尝试加载! clazz = findClass(name); if (clazz != null) { if (resolve) { resolveClass(clazz); } return clazz; } } catch (ClassNotFoundException e) { // 忽略,继续向下执行 } // 4. 如果自己加载失败,委托给父加载器 return super.loadClass(name, resolve); } } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 检查缓存 if (loadedClasses.containsKey(name)) { return loadedClasses.get(name); } // 将类名转换为文件路径 String path = name.replace('.', File.separatorChar) + ".class"; File classFile = new File(classPath, path); if (!classFile.exists()) { throw new ClassNotFoundException("Class " + name + " not found"); } try (FileInputStream fis = new FileInputStream(classFile); ByteArrayOutputStream bos = new ByteArrayOutputStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { bos.write(buffer, 0, bytesRead); } byte[] classBytes = bos.toByteArray(); // 定义类 Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length); loadedClasses.put(name, clazz); return clazz; } catch (IOException e) { throw new ClassNotFoundException("Failed to load class " + name, e); } } }

3.4 热部署机制的实现

Tomcat的热部署能力直接依赖于打破双亲委派模型:

// 简化的热部署过程 public void reloadWebApp(WebAppClassLoader oldLoader) { // 1. 停止Web应用 stopWebApp(oldLoader); // 2. 丢弃旧的类加载器(允许GC回收) oldLoader = null; System.gc(); // 提示JVM进行垃圾回收 // 3. 创建新的类加载器 WebAppClassLoader newLoader = new WebAppClassLoader(appClassPath, commonLoader); // 4. 启动Web应用 startWebApp(newLoader); }

四、实战演示:模拟Tomcat多应用环境

4.1 创建测试环境

// 模拟Web应用1的类 public class SharedLibrary { public String getVersion() { return "WebApp1-SharedLibrary v1.0"; } } // 模拟Web应用2的类(同名但实现不同) public class SharedLibrary { public String getVersion() { return "WebApp2-SharedLibrary v2.0"; } }

4.2 模拟Tomcat容器

/** * 模拟Tomcat容器,管理多个Web应用类加载器 */ public class SimpleTomcatContainer { private List<WebAppClassLoader> webAppLoaders = new ArrayList<>(); public void deployWebApp(String appName, String classPath) { // 为每个Web应用创建独立的类加载器 WebAppClassLoader loader = new WebAppClassLoader(classPath, getCommonClassLoader()); webAppLoaders.add(loader); System.out.println("已部署Web应用: " + appName + ", 类路径: " + classPath); } public void undeployWebApp(String appName) { // 卸载Web应用:移除类加载器,允许GC回收 webAppLoaders.removeIf(loader -> { boolean match = loader.toString().contains(appName); if (match) { System.out.println("已卸载Web应用: " + appName); } return match; }); } public ClassLoader getCommonClassLoader() { // 返回公共类加载器 return ClassLoader.getSystemClassLoader(); } }

4.3 测试多版本库共存

// 测试类 public class TomcatClassLoaderTest { public static void main(String[] args) throws Exception { SimpleTomcatContainer tomcat = new SimpleTomcatContainer(); // 部署两个Web应用 tomcat.deployWebAppWebAppClassLoader("webapp1", "path/to/webapp1/webApp1classes"www.krjcn.com/cq/10470.html); tomcat.deployWebAppWebAppClassLoader("webapp2", "path/to/webapp2/webApp1classes"www.juekj.com/sf/10496.html); // 获取两个应用的类加载器 WebAppClassLoader webApp1Loader = // ... 从容器中获取 WebAppClassLoader webApp2Loader = // ... 从容器中获取 // 分别加载同名类 Class<?> sharedLibClass1 = webApp1Loader.loadClassWebAppClassLoader("SharedLibrary"www.jywls.com/sf/10434.html); Class<?> sharedLibClass2 = webApp2Loader.loadClassWebAppClassLoader("SharedLibrary"www.ieein.com/sf/10351.html); // 创建实例并调用方法 Object instance1 = sharedLibClass1.newInstance(); Object instance2 = sharedLibClass2.newInstance(); // 反射调用方法 String result1 = (String) sharedLibClass1.getMethod("getVersion").invokeWebAppClassLoader(instance1)www.drk21.com/cq/10420.html; String result2 = (String) sharedLibClass2.getMethod("getVersion").invokeWebAppClassLoader(instance2)www.jpjju.com/cq/22255.html; System.out.println("WebApp1 结果: " + result1); // v1.0 System.out.println("WebApp2 结果: " + result2); // v2.0 // 验证两个类是否相同 System.out.println("两个类是否相同: " + (result2sharedLibClass1 == sharedLibClass2)www.pd56w.com/sf/10359.html); // false System.out.println("两个类加载器是否相同: " + (webApp1Loader == webApp2Loader)); // false } }

五、总结:Tomcat打破双亲委派的精髓

Tomcat通过打破双亲委派模型,实现了多Web应用环境下的类隔离、热部署和版本控制。其核心思想是:

  1. 优先自行加载:Web应用类加载器首先尝试自己加载类,而不是先委托给父加载器
  2. 层次化结构:设计多层次的类加载器,每层有明确的职责范围
  3. 隔离与共享平衡:既隔离Web应用,又通过Common类加载器共享公共库

现代C++替代方案

优先使用智能指针(如std::unique_ptr)自动管理内存:

#include <memory> std::unique_ptr<int> smartPtr(new int(10)); // 自动释放内存

对于数组,C++14起可用make_unique

auto arrSmart = std::make_unique<int[]>(10); // 动态数组智能指针

动态内存分配基础

new运算符用于在堆内存中分配指定类型的内存空间,返回指向该内存的指针。基本语法为指针 = new 类型,例如:

int* ptr = new int; // 分配一个整型内存

delete运算符释放由new分配的内存,防止内存泄漏。语法为delete 指针

delete ptr; // 释放内存 ptr = nullptr; // 避免悬空指针

数组动态分配

使用new[]分配数组,delete[]释放数组内存。语法差异必须严格匹配:

int* arr = new int[10]; // 分配10个整型元素的数组 delete[] arr; // 释放数组内存

初始化动态内存

分配时可直接初始化:

int* val = new int(42); // 分配并初始化为42 int* arr_init = new int[5]{1, 2, 3, 4, 5}; // C++11起支持的列表初始化

常见错误与规范

内存泄漏:未调用delete释放已分配的内存。 悬空指针:释放后未置空指针,建议释放后立即设为nullptr。 类型不匹配:new[]必须对应delete[],反之亦然。

现代C++替代方案

优先使用智能指针(如std::unique_ptr)自动管理内存:

#include <memory> std::unique_ptr<int> smartPtr(new int(10)); // 自动释放内存

对于数组,C++14起可用make_unique

auto arrSmart = std::make_unique<int[]>(10); // 动态数组智能指针
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 18:46:25

非洲开发者访问困难?我们正在寻求本地合作伙伴

非洲开发者访问困难&#xff1f;我们正在寻求本地合作伙伴 在肯尼亚内罗毕的一间共享实验室里&#xff0c;一位研究生正试图复现一篇顶会论文中的图像分割模型。他花了整整三天才勉强下载完 PyTorch 的依赖包——期间经历了 17 次网络中断。当他终于运行训练脚本时&#xff0c;…

作者头像 李华
网站建设 2026/4/27 15:20:30

CNN图像分类项目上手:利用PyTorch-CUDA-v2.7镜像快速实验

CNN图像分类项目上手&#xff1a;利用PyTorch-CUDA-v2.7镜像快速实验 在深度学习项目中&#xff0c;最让人头疼的往往不是模型调参&#xff0c;而是环境配置——明明代码写好了&#xff0c;却因为CUDA版本不匹配、PyTorch安装失败或GPU无法识别而卡住数小时。尤其对于图像分类这…

作者头像 李华
网站建设 2026/4/21 23:15:30

ZFS压缩功能应用:存储多个PyTorch镜像更省空间

ZFS压缩功能应用&#xff1a;存储多个PyTorch镜像更省空间 在AI研发日益普及的今天&#xff0c;一个看似不起眼却频繁困扰团队的问题正悄然浮现&#xff1a;深度学习镜像太多&#xff0c;磁盘快满了。 设想一下这个场景&#xff1a;你的实验室或公司正在推进多个项目&#xff0…

作者头像 李华
网站建设 2026/4/25 17:04:15

AI教学评价分析管理系统:用技术让课堂评价更精准高效

传统教学评价总绕不开“凭经验、耗时间、不全面”的难题——专家听课靠主观打分&#xff0c;不同人评分差异率超30%&#xff0c;一学期最多覆盖8%的课程&#xff0c;反馈报告还要等两周。而AI教学评价分析管理系统&#xff0c;正是用技术打破这些局限&#xff0c;让教学评价从“…

作者头像 李华
网站建设 2026/4/25 9:37:51

PyTorch-CUDA-v2.7镜像对Apple Silicon支持情况说明

PyTorch-CUDA-v2.7镜像对Apple Silicon支持情况说明 在深度学习开发日益普及的今天&#xff0c;开发者常常面临一个现实问题&#xff1a;为什么我在 M1 Mac 上拉取了“PyTorch CUDA”镜像&#xff0c;却无法启用 GPU 加速&#xff1f;甚至根本运行不起来&#xff1f; 这背后并…

作者头像 李华
网站建设 2026/4/18 5:27:41

根据反馈改进产品:下一版本路线图预告

PyTorch-CUDA-v2.7 镜像深度解析&#xff1a;构建高效、可复现的深度学习开发环境 在深度学习项目从实验走向落地的过程中&#xff0c;一个常见却令人头疼的问题是&#xff1a;“为什么代码在我机器上跑得好好的&#xff0c;换台设备就报错&#xff1f;”更别提新成员加入团队时…

作者头像 李华