浅谈c语言 内存溢出和内存泄漏

内存溢出&内存泄漏 (C语言)

写在前面:

​ c语言中常见的内存管理问题,代码检查非常困难,众多程序Bug均来自它们,指针功能非常强大,但是程序可读性较差,对新手极其不友好。但是如果你掌握空指针 野指针指针运算,知道二级指针 指针数组 数组指针请跳过。使用指针有很多不可控事件发生,如硬件开发中极容易出现烧毁电路甚至炸电容的事情发生,所以能不用指针就尽量不要用。

尽量 不要 不要 不要 不要 使用 指针!!!

1.内存泄漏(Memory Leak)

内存泄漏

动态内存分配后未能正确释放内存,导致内存资源无法被回收利用,随着程序运行,为释放的内存堆积,最终导致内存耗尽,性能下降和程序崩溃。

内存泄漏主要原因:

1.1.指针重新赋值:

void test(int* ps){
  ps = 10; //此时ps就是一个指针
}

1.2.错误的内存释放

  • 栈的错误内存示范
/*数组方式的结构,不释放ps,而是释放数组中动态开辟空间的区域ps->a

*/
typedef int STDataType;
typedef struct Stack{
    int top; //栈顶 数据个数
    int capacity; //空间
    STDataType* a; //数据容器
}ST;
/*销毁栈 示例*/
void StackDestory(ST* ps){
    assert(ps);
    ps->top = 0;
    ps->capacity = 0;
//  free(ps); //错误的内存释放
    free(ps->a); //示例~~~~~~~~~~~~~~~~~~~~
    ps->a = NULL; //防御性编程,指针置空,同时无法再访问导致野指针出现
}
  • 队列的错误内存释放
//数据存储结构
typedef struct QueueNode{
    QDataType data;
    struct QueueNode* next;
}QNode;

//队头指针和队尾指针
typedef struct Queue{
    QNode* head; //队尾
    QNode* tail; //队尾
}QUeue;
//示例
void QueueDestory(QUeue* pq){
    assert(pq);
    while (pq->head != NULL){
        QNode* temp = pq->head; //让temp指向第一个节点
        pq->head = pq->head->next; //防止队头指针释放,让头指针指向下一个指针
        free(temp); 
    }
    pq->head = pq->tail = NULL; //队头队尾指针置空
}

1.3.返回值的不正确处理

int text(int* a){
  	a = 20;
}
//main函数
int as = 10;
test(&as); //int* ab = test(&as); 返回值的不正确处理

导致的后果:

  • 系统性能下降
  • 可用内存被耗尽
  • 程序崩溃,特别是在长时间运行的程序中(如服务器)

2.内存溢出(Memory Overflow)

栈区堆区和缓冲区的关系

2.1数组越界和指针错误
int arr[2]; //0 1
for (int i = 0; i < 3; i++){	//0 1 2 
  arr[i] = i;
}
2.2栈溢出
void stackOverflow() {
    int array[10000]; // 分配一个大数组,消耗栈内存
    stackOverflow();   // 递归调用
}
int main() {
    stackOverflow(); // 触发栈溢出
    return 0;
}
2.3堆溢出
int main() {
    while (1) {
        // 不断分配大量内存,导致堆溢出
        int *ptr = (int *)malloc(100000000 * sizeof(int)); 
        if (ptr == NULL) {
            exit(-1);
            break;
        }
    }
    return 0;
}
2.4缓冲区溢出 -数组越界
void bufferOverflow() {
    char buffer[10];
    for (int i = 0; i <= 10; i++) { // 越界写入 buffer[10]
        buffer[i] = 'a'; // 访问超出边界的内存
    }
}
int main() {
    bufferOverflow(); // 触发缓冲区溢出
    return 0;
}

导致的后果:

  • 数据损坏
  • 安全漏洞
  • 系统不稳定
  • 程序崩溃

tip: 销毁指针时候将指针置空是一种防御性编程,首先防止误用已经被释放的内存,其次提高了代码的健壮性。

3. 区别

特性内存溢出(Memory Overflow)内存泄漏(Memory Leak)
定义访问超出分配的内存范围动态分配的内存没有被释放
常见原因数组越界、指针错误、未检查边界条件使用 malloc 等动态分配后,未使用 free 释放
表现形式程序崩溃、数据损坏、未定义行为、系统异常内存被逐渐耗尽,程序运行缓慢,内存耗尽导致崩溃
常见影响程序可能立即崩溃或出现错误行为随着时间推移,内存会逐渐消耗,导致系统资源不足
解决方法避免数组越界、使用有效的边界检查在使用完动态内存后,确保调用 free 释放内存

4.防止内存溢出和内存泄漏的建议

防止内存溢出:

  • 边界检查
  • 使用调试工具
  • 初始化指针

防止内存泄漏:

  • 动态内存管理
  • 跟踪内存分配
  • 工具检测
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值