【C++ 面试 - 内存管理】每日 3 题(八)

news2024/9/23 3:15:58

✍个人博客:Pandaconda-CSDN博客

📣专栏地址:http://t.csdnimg.cn/fYaBd

📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

22. delete p 和 delete[] p 的区别

在 C++ 中,deletedelete[] 都是用于释放通过 newnew[] 分配的内存,但它们的使用场景是不同的。

delete p 用于释放单个对象的内存。这意味着在使用 new 分配内存后,如果你只用一个指针指向这个对象,就应该使用 delete p 来释放内存。例如:

int* p = new int;
// 使用 p 指针操作对象
delete p; // 释放内存

delete[] p 用于释放数组对象的内存。这意味着在使用 new[] 分配内存后,如果你用一个指针指向一个数组的起始地址,就应该使用 delete[] p 来释放内存。例如:

int* p = new int[10];
// 使用 p 指针操作数组对象
delete[] p; // 释放内存

使用 delete 释放数组对象的内存或者使用 delete[] 释放单个对象的内存,会导致未定义的行为(Undefined Behavior),可能会导致内存泄漏或程序崩溃。

因此,当我们使用 newnew[] 分别分配单个对象和数组对象时,需要确保使用与其对应的 deletedelete[] 来正确释放内存,以避免内存泄漏和其他潜在问题。

23. new 和 delete 的实现原理,delete 是如何知道释放内存的大 小的?

1、 new 简单类型直接调用 operator new 分配内存;而对于复杂结构,先调用 operator new 分配内存,然后在分配的内存上调用构造函数。

对于简单类型,new[] 计算好大小后调用 operator new;

对于复杂数据结构,new[] 先调用 operator new[] 分配内存,然后在 p 的前四个字节写入数组大小 n,然后调用 n 次构造函数,针对复杂类型,new[] 会额外存储数组大小;

① new 表达式调用一个名为 operator new (operator new[]) 函数,分配一块足够大的、原始的、未命名的内存空间;

② 编译器运行相应的构造函数以构造这些对象,并为其传入初始值;

③ 对象被分配了空间并构造完成,返回一个指向该对象的指针。

2、 delete 简单数据类型默认只是调用 free 函数;复杂数据类型先调用析构函数再调用 operator delete。

针对简单类型,delete 和 delete[] 等同。假设指针 p 指向 new[] 分配的内存。因为要 4 字节存储数组大小,实际分配的内存地址为 [p-4],系统记录的也是这个地址。delete[] 实际释放的就是 p-4 指向的内存。而 delete 会直接释放 p 指向的内存,这个内存根本没有被系统记录,所以会崩溃。

3、 需要在 new[] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了。

24. 什么是内存泄露,如何检测与避免?

(1)内存泄露

一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的 (内存块的大小可以在程序运行期决定) 内存块,使用完后必须显式释放的内存。应用程序般使用 malloc、realloc、new 等函数从堆中分配到块内存,使用完后,程序必须负责相应的调用 free 或 delete 释放该内存块。否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

  

(2)避免内存泄露的几种方式

  1. 使用智能指针:智能指针是一种能够自动管理内存的对象,可以在不再需要对象时自动释放内存。C++ 标准库提供了智能指针类型,如 std::unique_ptr 和 std::shared_ptr,可以使用它们来管理动态分配的内存。

  2. 析构函数为虚函数:一定要将基类的析构函数声明为虚函数

  3. 申请和释放操作成对出现:有 new 就有 delete,有 malloc 就有 free,保证它们一定成对出现。对象数组的释放一定要用 delete[]

  4. 重载 new 和 delete:手动管理内存时,应该重载 new 和 delete 运算符,以便在分配和释放内存时使用适当的函数。这可以避免使用不当的指针操作,从而减少内存泄漏的风险。

  5. 使用 RAII(资源获取即初始化)的思想:RAII 是一种编程技术,它通过将资源的生命周期与对象的生命周期关联起来,确保资源在使用后被正确释放。在 C++ 中,可以使用类来封装动态分配的资源,并在类对象的生命周期结束时自动释放资源。

  6. 预先设定好内存池:预先设定好内存池可以减少频繁的内存分配和释放操作,从而减少内存碎片和提高性能。在程序开始时,可以预先分配一定数量的内存块,并在需要时从内存池中分配内存。这样可以避免频繁地调用 new 和 delete 运算符,从而减少错误的可能性。

(3)检测方法

1. 计数法

使用 new 或者 malloc 时,让该数 +1,delete 或 free 时,该数 -1,程序执行完打印这个计数,如果不为 0 则表示存在内存泄露。

2. gcc 启用 asan 标志检查

GCC 中的 “启用 ASAN 标志检查” 是一种内存泄漏检测工具,它是 GCC 编译器的一个特性,称为 AddressSanitizer(ASan)。ASan 是一个动态分析工具,它可以检测程序中可能的内存泄漏和其他内存错误。

当你在编译程序时,添加 ASan 标志可以启用内存泄漏检测。当程序运行时,ASan 会跟踪分配和释放的内存,并检查是否存在未被释放的内存块。如果发现未被释放的内存块,ASan 会报告内存泄漏。

使用 ASan 进行内存泄漏检测的一般步骤如下:

  • 安装 GCC 编译器并启用 ASan 标志。

  • 编写代码,使用智能指针或 RAII 技术管理内存。

  • 编译程序时添加 ASan 标志。

  • 运行程序并检查任何内存泄漏报告。

3. 标记清除法(Mark-Sweep Garbage Collection)

标记清除法是一种内存泄漏检测方法,用于检测程序中可能存在的内存泄漏问题。标记清除法主要包括两个步骤:标记和清除。

在程序运行过程中,标记清除法会跟踪分配和释放的内存块,并使用标记来标识可能存在问题的内存区域。这些标记通常是由程序中的特定对象或数据结构来管理的。当程序运行到某个特定点时,标记清除法会遍历所有已分配的内存块,并检查每个内存块的状态。如果某个内存块已经被释放,但仍然被引用或使用,那么这个内存块就被认为是内存泄漏。

清除步骤则是将所有标记清除,以防止后续的引用或使用。在清除过程中,标记清除法会再次遍历所有已分配的内存块,并确保每个内存块的状态都被正确地清除。

标记清除法的优点在于它可以检测到内存泄漏问题,并且可以在程序运行时实时检测和报告问题。然而,它也存在一些缺点,例如可能会影响程序的性能和稳定性,尤其是在大规模程序中。此外,标记清除法需要正确地管理内存和跟踪分配和释放的操作,因此需要编写复杂的代码来正确地实现它。

4. Linux 下可以使用 Valgrind 工具

首先看一段 C 程序示例,比如:

#include <stdlib.h>
int main()
{
    int *array = malloc(sizeof(int));
    return 0;
}

编译程序:gcc -g -o main main.c,比哪一需要加上 -g 选项打开调试,使用 IDE 的可以用 Debug 模式编译。

使用 Valgrind 检测内存使用情况:

valgrind --tool=memcheck --leak-check=full ./main

结果:

==31416== Memcheck, a memory error detector
==31416== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31416== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31416== Command: ./main_c
==31416==
==31416==
==31416== HEAP SUMMARY:
==31416==     in use at exit: 4 bytes in 1 blocks
==31416==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==31416==
==31416== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31416==    at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==31416==    by 0x400537: main (main.c:5)
==31416==
==31416== LEAK SUMMARY:
==31416==    definitely lost: 4 bytes in 1 blocks
==31416==    indirectly lost: 0 bytes in 0 blocks
==31416==      possibly lost: 0 bytes in 0 blocks
==31416==    still reachable: 0 bytes in 0 blocks
==31416==         suppressed: 0 bytes in 0 blocks
==31416==
==31416== For counts of detected and suppressed errors, rerun with: -v
==31416== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

先看看输出信息中的 HEAP SUMMARY,它表示程序在堆上分配内存的情况,其中的 1 allocs 表示程序分配了 1 次内存,0 frees 表示程序释放了 0 次内存,4 bytes allocated 表示分配了 4 个字节的内存。

另外,Valgrind 也会报告程序是在哪个位置发生内存泄漏。例如,从下面的信息可以看到,程序发生了一次内存泄漏,位置是 main.c 文件的第 5 行:

==31416== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31416==    at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==31416==    by 0x400537: main (main.c:5)

5. Win dows 下可以使用 CRT库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2086002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频压缩工具哪个好?视频压缩工具安利

还在为视频文件过大而烦恼吗&#xff1f;想要快速分享或上传视频却受限于空间或时间&#xff1f; 别担心&#xff0c;今天我来告诉你们&#xff1a;视频压缩成文件怎么弄。 无需复杂操作&#xff0c;轻松几步&#xff0c;就能让你的视频文件瘦身成功&#xff0c;既保留关键内…

深度学习基础—结构化机器学习项目

1.正交化 这是一个老式电视&#xff0c;有一组旋钮可以对画面进行调节&#xff0c;例如高度、宽度、画面梯形角度、画面位置、画面旋转等等&#xff0c;但是如果有一个旋钮&#xff0c;旋转时可以调节上面所有参数&#xff0c;那么就会出现一种情况&#xff1a;当前的画面高度和…

jconsole远程连接

jconsole可以远程连接的前提&#xff08;需要在部署应用时像下面示例这样设置&#xff09;&#xff1a; -Djava.rmi.server.hostname127.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port3214 -Dcom.sun.management.jmxremote.sslfalse -Dcom.sun.m…

milvus使用milvus migration工具迁移数据

1.前提&#xff1a;这个数据迁移工具是collection 维度的 2.文章内是2.3.1–》2.4.5数据迁移&#xff0c;公司内部需求&#xff0c;各位看官注意哈 官方架构图&#xff1a; 想要迁移的milvus 官方称之为&#xff1a;源source milvus 要迁入的表 目标的milvus 官方称之为&…

JWT结构详解与JWT设置

JWT结构详解与JWT设置 1. 什么是token2. 为什么要使用token3. 什么是JWT4. JWT的格式4.1 header4.2 payload4.3 signature 5. JWT校验流程6. JWT使用案例6.1 token的创建6.2 判断token是否可以刷新6.3 刷新token6.4 token的校验6.5 用户验证流程 1. 什么是token Token是服务端…

Prometheus+Grafana的安装和入门

概念 什么是Prometheus? Prometheus受启发于Google的Brogmon监控系统&#xff08;相似kubernetes是从Brog系统演变而来&#xff09;&#xff0c; 从 2012年开始由google工程师Soundclouds使用Go语言开发的开源监控报警系统和时序列数据库 (TSDB)。&#xff0c;并且与2015年早…

2017年系统架构师案例分析试题一

目录 案例 【题目】 【问题 1】(12 分) 【问题 2】(13 分) 答案 【问题 1】答案 【问题 2】答案 相关推荐 案例 阅读以下关于软件架构评估的叙述&#xff0c;在答题纸上回答问题 1 和问题 2。 【题目】 某单位为了建设健全的公路桥梁养护管理档案&#xff0c;拟开发一套公…

USB PHY—— PHY 基础

芯片厂商开发了一些 USB PHY 芯片&#xff0c;可以把 DP、DM上的差模信号转成共模信号。 USB PHY 负责最底层的信号转换&#xff0c;作用类似于网口的 PHY。 USB 信号传输前&#xff0c;需要通过 PHY 把 USB 控制器的数字信号转成线缆上的模拟信号。USB 控制器和 PHY 之间的总…

中国严肃游戏开发的最佳实践

严肃游戏产业在中国迅速发展&#xff0c;将娱乐与教育、培训和宣传活动融为一体。旨在实现特定学习成果或行为改变的严肃游戏在从企业培训到医疗保健和教育的各个领域越来越受欢迎。然而&#xff0c;为中国市场开发成功的严肃游戏需要深入了解当地文化、用户偏好和技术趋势。以…

函数栈帧的创建和销毁(VS2022)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、前面的困惑 二、什么是函数栈帧 三、关于函数栈帧的基础知识 1.栈 2.寄存器 2.1 什么是寄存器 2.2 相关的寄存器 2.3 相关汇编命令 2.4 预备知识 四、解析函数…

盘点4款可以免费使用的高效ai PPT制作工具。

平时我们自己制作一个PPT还是需要比较长的时间的&#xff0c;从构思内容&#xff0c;到制作主题和逻辑框架&#xff0c;然后是挑选模板、排版配色等&#xff0c;过程比较繁琐且费时。但是&#xff0c;现在出现了很多的AIPPT制作工具&#xff0c;能够快速的帮助用户生成一个完整…

来自工业界的知识库 RAG(六),独特的 RAG 框架 dsRAG 核心亮点解读

背景介绍 在前面介绍了较多的开源 RAG 框架&#xff0c;比如主打 Rerank 的 QAnything, 主打精细文件解析的 RagFlow, 主打模块化灵活组合的 GoMate。这些库的设计除了少量的独特之处外&#xff0c;相似的部分很多。 最近有注意到一款另类的 RAG 框架 dsRAG&#xff0c;使用了…

openGauss在龙芯平台部署的实践

服务器环境 系统信息 NAME"Loongnix-Server Linux" VERSION"8" ID"loongnix-server" ID_LIKE"rhel fedora centos" VERSION_ID"8" PLATFORM_ID"platform:lns8" PRETTY_NAME"Loongnix-Server Linux 8"…

第四十篇-TeslaP40+Ollama+Ollama-WebUI(自编译)

本文介绍用自己编辑ollama-webui,链接本地ollama 环境 系统&#xff1a;CentOS-7 CPU: 14C28T 内存&#xff1a;32G 显卡&#xff1a;Tesla P40 24G 驱动: 535 CUDA: 12.2 Ollama: 0.3.0本地ollama 参考 [第二十四篇-Ollama-在线安装](https://blog.csdn.net/hai4321/articl…

2024软考:一场与“难”共舞的奇妙冒险,你值得拥有!

在这个时代&#xff0c;如果说有什么考试能让IT界的勇士们闻风丧胆&#xff0c;又爱又恨&#xff0c;那软考绝对能C位出道&#xff0c;成为众多技术大佬心中的“白月光”与“朱砂痣”。随着岁月悠悠&#xff0c;2024年的软考似乎又悄悄地在难度上动了点小心思&#xff0c;让人不…

vue设置水印

水印图例 1.新建Watermark.js 文件 const watermark {}const setWatermark (text, sourceBody) > {const id Math.random() * 10000 - Math.random() * 10000 / Math.random() * 10000if (document.getElementById(id) ! null) {document.body.removeChild(document.getE…

阿里云服务器开放端口的完整版图文教程

原文&#xff1a;阿里云服务器开放端口完整版教程&#xff1a;https://www.yundashi168.com/488.html 笔者近期开发完成的服务端程序部署在阿里云的ECS云服务器上面&#xff0c;一些应用程序配置文件需要设置监听的端口&#xff08;如Tomcat的8080、443端口等&#xff09;&…

萤石云 移动端demo指南

再来一篇&#xff0c;这次是萤石开放平台移动端demo的使用指南 一、Demo使用指南 从官网下载demo&#xff0c;下载地址demo首页如下&#xff1a; 填入对应参数 输入框是否必填解释服务器区域是国内选择Asia-China&#xff0c;海外选择对应的区域。选择后ApiUrl和WebUrl会自动…

餐饮行业eHR人力资源管理系统应该如何选择?

数字化转型与增长成为餐饮企业品牌竞争的创新壁垒&#xff0c;越来越多的餐饮企业&#xff08;门店&#xff09;依托数字化工具和手段&#xff0c;覆盖从内部组织到外部的数字化升级&#xff0c;包括员工管理、营销、客户管理&#xff0c;以及采购供应链等各环节的数字化运营。…

Netty从入门到超神-NIO 三大核心(selector,channel,buffer)(二)

前言 上一篇文章认识了一下Java的三大IO&#xff0c;这一章节我们详细了解一下NIO的工作原理以及三大核心Selector,Channel,Buffer并尝试来做一些小案例。 Java NIO 模型 Java NIO有三个核心的组件&#xff1a; selector 选择器 &#xff0c; channel 通道 &#xff0c; buf…