news 2026/1/26 23:53:46

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/1/26 19:39:34

自然语言处理开发提速50%:PyTorch-CUDA-v2.7镜像实测报告

自然语言处理开发提速50%&#xff1a;PyTorch-CUDA-v2.7镜像实测报告 在自然语言处理项目中&#xff0c;你是否经历过这样的场景&#xff1f;花费一整天时间搭建环境&#xff0c;却因为CUDA版本与PyTorch不兼容导致import torch直接报错&#xff1b;好不容易跑通代码&#xff0…

作者头像 李华
网站建设 2026/1/27 0:00:10

大模型学习路径:从入门到实践的循序渐进指南

前言 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的爆发式发展彻底重塑了人工智能领域的格局&#xff0c;从DeepSeek的全民热议到文心一言、Llama等模型的百花齐放&#xff0c;大模型已经渗透到智能问答、内容创作、代码生成、数据分析等众多领域&#xff0c;成为…

作者头像 李华
网站建设 2026/1/19 1:27:21

PyTorch-CUDA-v2.7镜像对ARM64架构支持现状

PyTorch-CUDA-v2.7 镜像在 ARM64 架构上的支持现状分析 在边缘计算与嵌入式 AI 应用快速发展的今天&#xff0c;越来越多的开发者开始将深度学习模型部署到非传统 x86 服务器平台上。NVIDIA Jetson 系列、AWS Graviton 实例以及各类基于 ARM64 的 SoC 设备正逐步成为推理场景的…

作者头像 李华
网站建设 2026/1/19 2:59:34

Gradient Scaling原理与实现:PyTorch-CUDA-v2.7自动混合精度

Gradient Scaling原理与实现&#xff1a;PyTorch-CUDA-v2.7自动混合精度 在当今深度学习模型动辄上百亿参数的背景下&#xff0c;训练效率和显存占用已成为制约研发进度的核心瓶颈。以视觉大模型ViT-30B或语言模型LLaMA-65B为例&#xff0c;若全程使用FP32浮点运算&#xff0c;…

作者头像 李华
网站建设 2026/1/25 3:07:48

亚洲区域访问延迟优化:新增上海、新加坡缓存服务器

亚洲区域访问延迟优化&#xff1a;新增上海、新加坡缓存服务器 在AI研发日益全球化的今天&#xff0c;一个看似微小的技术细节——镜像拉取速度&#xff0c;正悄然影响着成千上万开发者的日常效率。尤其对于身处亚洲的团队而言&#xff0c;每次启动训练任务前长达十几分钟的环境…

作者头像 李华
网站建设 2026/1/19 10:42:43

Google Colab替代方案:自建PyTorch-CUDA-v2.7云端实验室

自建 PyTorch-CUDA 云端实验室&#xff1a;突破 Colab 瓶颈的高效实践 在深度学习项目日益复杂的今天&#xff0c;很多开发者都经历过这样的场景&#xff1a;凌晨两点&#xff0c;模型训练正进行到第80个epoch&#xff0c;突然浏览器弹出“运行时已断开”——Google Colab 又挂…

作者头像 李华