内存泄漏出现的时机和原因,如何避免?

news/2025/3/10 9:09:33/

由于时间比较紧张我就不排版了,但是对于每一种可能的情况都会出对应的代码示例以及解决方案代码示例。

内存泄漏可能的原因之一在于用户在动态分配一个内存空间之中,忘记将这部分内容手动释放。例如:(c++之中使用new分配内存没有使用delete释放,或者c语言使用malloc分配内容没有使用free释放)

#include<iostream>
using namespace std;
int main(){
    int* num=new int(10);
    return 0;
}

这部分内容没有对num进行delete内存释放,导致内存泄漏。

需要注意的是内存泄漏并不是内存直接漏出去,而是指部分应该被回收的内存没有被回收或者错误的被跳过导致没有正确的回收,导致内存越来越多占据了大量的内存空间,可分配的内存越来越少,影响性能。

如何避免:

通过手动释放这部分内容:

#include<iostream>
using namespace std;
int main(){
    int* num=new int(10);
    delete num;
    return 0;
}

内存泄漏的原因二:没有书写析构函数,导致一部分动态分配的内存没有被释放或者析构函数被遗漏调用。例如基类的析构函数没有被派生类重写,导致当通过基类指针删除派生类时,只调用了基类的析构函数,派生类本身的一部分动态分配的内存没有被释放,导致一部分内容没有被正确的释放,这是析构函数被遗漏时可能发生的情况。解决方法:添加析构函数或者在书写成虚方法的析构函数对其进行方法重写。

#include<iostream>
using namespace std;
class Test{
    private:
        int* num;
    public:
        Test(){
            num=new int(10);
        }
        ~Test(){
            delete num;
        }
};
int main(){
    Test test;
    return 0;
}

原因三:使用的内存被循环的引用,导致引用计数始终不为0,例如使用智能指针shared_ptr,当两个类相互的调用对方的智能指针时,引用计数始终不为0,这部分内容不会被正确的释放。例如:

#include<iostream>
#include<memory>
using namespace std;
class B;
class A{
    public:
        shared_ptr<B> b_ptr;
};
class B{
    public:
        shared_ptr<A> a_ptr;
};
int main(){
    shared_ptr<A> a=make_shared<A>();
    shared_ptr<B> b=make_shared<B>();
    a->b_ptr=b;
    b->a_ptr=a;
    return 0;
}

始终持有对方的智能指针的引用,引用计数始终不清零。

更改建议:可以使用weak_ptr打破循环引用:

例如:

#include<iostream>
#include<memory>
using namespace std;
class B;
class A{
    public:
        shared_ptr<B> b_ptr;
};
class B{
    public:
        weak_ptr<A> a_ptr;
};
int main(){
    shared_ptr<A> a=make_shared<A>();
    shared_ptr<B> b=make_shared<B>();
    a->b_ptr=b;
    b->a_ptr=weak_ptr<A>(a);
    return 0;
}

原因四:程序虽然正确的书写了delete对内容进行释放,但是被异常抛出的错误跳过了内存释放,导致内存释放的部分被跳过,没有正确的释放这部分内存空间,举例说明:

#include<iostream>
#include<stdexcept>
using namespace std;
void func(){
    int* num=new int(10);
    throw runtime_error("Exception");
    delete num;
}
int main(){
    try{
        func();
    }
    catch(const exception& error){
        cout<<error.what()<<endl;
    }
    return 0;
}

这部分由于抛出异常被跳过内存释放,我们可以使用智能指针unique_ptr,使其在异常抛出之后自动的释放这一部分内存,就不会发生这种异常,举例说明:

#include<iostream>
#include<memory>
#include<stdexcept>
using namespace std;
void func(){
    unique_ptr<int> u=make_unique<int>(10);
    throw runtime_error("Exception");
}
int main(){
    try{
        func();
    }
    catch(const exception& error){
        cout<<error.what()<<endl;
    }
    return 0;
}
        

原因5:资源管理对象的生命周期不当,没有在正确的时机管理释放内存。

老规矩,作为一名unity开发程序员,我们来思考C#之中存在哪一些内存泄漏(简单说一下吧,之前在博客之中有详细的描述)

C#之中如果事件订阅未被取消也会导致内存泄漏,所以我们说事件的添加和移除应该是成双成对出现的。另外一些使用lambda表达式的委托无法安全的移除,这时候尽量不要使用lambda表达式防止内存泄漏。另外一个静态变量无法被内存回收,如果静态变量引用了一些对象,这部分内容是无法被垃圾回收的。

C#相对于C++的内存泄漏问题比较少,这是由于C#的自动垃圾回收机制,会自动对一部分内存进行回收,大大降低了内存泄漏的风险,对于C++来说错误遗漏没有进行delete释放或者使用delete释放之后又使用了已经被释放的内容会出现悬空指针的问题。

C#的内存泄漏排查也相对于C++来说比较容易。不过,在使用非托管资源(如文件、网络连接等)时,仍需要手动管理资源的释放。


http://www.ppmy.cn/news/1578036.html

相关文章

基于Python的电商销售数据分析与可视化系统实

一、系统架构设计 1.1系统流程图 #mermaid-svg-Pdo9oZWrVHNuOoTT {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Pdo9oZWrVHNuOoTT .error-icon{fill:#552222;}#mermaid-svg-Pdo9oZWrVHNuOoTT .error-text{fill:#5…

【AI赋能】AI 工具生成视频教材:从创意到成品的全流程指南

AI 工具生成视频教材&#xff1a;从创意到成品的全流程指南 目标 通过本教材&#xff0c;您将学会如何利用 AI 工具&#xff08;Grok、Sora、Speechify 和 CapCut&#xff09;生成一个完整的视频&#xff0c;包括脚本生成、视频片段制作、字幕添加、音频生成以及最终剪辑合成…

《加快应急机器人发展的指导意见》中智能化升级的思考——传统应急设备智能化升级路径与落地实践

感谢阅读本次内容分享&#xff0c;下面我将解读分析《加快应急机器人发展的指导意见》&#xff0c;喜欢的点赞支持一下呗~(日更真的很辛苦~)&#xff0c;欢迎评论区留言讨论&#xff0c;你们的发言我都会看到~ 《加快应急机器人发展的指导意见》中智能化升级的思考——传统应急…

计算机视觉图像点运算【灰度直方图均衡化图形界面实操理解 +开源代码】

对一个数字图像处理系统来说&#xff0c;一般的处理过程为三个步骤&#xff1a;图像预处理、特征抽取、图像识别和分析。图像的点运算就是预处理过程中的重要一步&#xff0c;点运算是对图像的灰度级进行变换。 图像点运算概念 点运算是指对图像的每个像素依次进行相同的灰度变…

计算机基础知识总结(八股文总结----计算机网络、操作系统、数据库、c++、数据结构与算法)

一、操作系统 0.内存管理 01.什么是虚拟内存&#xff1f;为什么需要虚拟内存&#xff1f; 虚拟内存为程序提供比实际物理内存更大的内存空间&#xff0c;同时提高内存管理的灵活性和系统的多任务处理能力。虚拟地址空间就是进程所能看到的内存空间&#xff0c;这段空间是连续…

学习前置知识第18和19天

今天要做什么&#xff1f; 1&#xff1a;显示数字要求格式 2&#xff1a;无符号除法指令:div 3&#xff1a;前面用vhd和img等格式进行系统界面启动&#xff0c;详细了解多种镜像格式文件的区别 一&#xff1a;显示数字要求格式 屏幕上显示的数字格式,三个颜色编码和数字属性 1&…

国庆星期几 (2012年蓝桥杯国赛)

题目描述: 1949年的国庆节 (10月1日) 是星期六。今年 (2012) 的国庆节是星期一。那么, 从建国到现在, 有几次国庆节正好是星期日呢? 思路解析&#xff1a; 1. 核心目标 统计从1950年到2012年之间&#xff0c;每年10月1日是星期天的次数。 通过累计每年的总天数并取模运算&am…

WPF基础知识81-100

控件与自定义控件开发 81.如何在 WPF 中创建一个自定义的可拖动控件&#xff1f; 答案&#xff1a;可以通过处理鼠标事件来实现控件的拖动功能。主要处理 MouseLeftButtonDown、MouseMove 和 MouseLeftButtonUp 事件。在 MouseLeftButtonDown 事件中记录鼠标的初始位置和控件…