关于c++内存回收(delete)对程序整体运行时间影响的疑问

在实现红黑树时,作者发现删除节点时使用delete回收内存导致程序运行时间显著增加。即使在清空后,程序状态看似恢复原样,但后续运行时间异常。经过一系列测试,包括改变数据规模、使用链表测试和对比不同代码,确认问题与delete操作有关。目前尚不清楚为何回收内存反而会增加运行时间,作者寻求对此现象的解释。
摘要由CSDN通过智能技术生成

起因是这样的,最近算法课在上红黑树,写红黑树的时候肯定涉及一些内存管理的问题,主要是在插入结点的时候要用new分配一个新的结点,并在清空红黑树的时候把这些结点delete释放掉。

算法导论书上只提供了插入和删除操作的代码,但是因为要测试多组数据的运行时间,需要自己实现一个清空(destroy)操作。本着避免一切可能造成的内存泄漏的原则,一开始我写了完整的清空函数,也就是从根节点开始递归,回收每个结点的内存空间,其中我的结点和树定义如下。

enum RBTColor{
   RED, BLACK};

class RBTNode {
   
public:
    RBTColor color;
    int key;
    RBTNode *lson;
    RBTNode *rson;
    RBTNode *parent;
    RBTNode(RBTColor c, int k) {
   
        color = c;
        key = k;
        lson = rson = parent = NULL;
    }
};
class RBTree {
   
public:
    RBTree() {
   
        root = NULL;
    }
    void destroy() {
   
        destroy(root);
    }
private:
    void destroy(RBTNode *&root) {
   
        if (root == NULL) return ;
        if (root->lson) destroy(root->lson);
        if (root->rson) destroy(root->rson);
        delete root;
        root = NULL;
    }
}rb_tree;

然而运行时感觉运行时间很奇怪,于是修改测试数据,测了5组规模一样的数据,发现只有第一次的运行时间是正常的,后面四次的时间明显大很多。进一步记录了一下destroy函数所占用的时间,结果如下。

destroy time : 0 ms SIZE : 100000 RUNTIME : 71 ms
destroy time : 46 ms SIZE : 100000 RUNTIME : 3308 ms
destroy time : 38 ms SIZE : 100000 RUNTIME : 2442 ms
destroy time : 38 ms SIZE : 100000 RUNTIME : 3415 ms
destroy time : 39 ms SIZE : 100000 RUNTIME : 2267 ms
destroy time : 38 ms

意识到可能是destroy的过程中的某些操作产生了这样的结果,采取控制变量法,尝试去掉了内存回收的部分之后运行时间时间恢复正常。修改后的destroy和测试结果如下,但很明显,这样写又会有内存泄漏的问题,即没有在清空红黑树前回收每个结点的内存

void destroy() {
   
    // clock_t rec = clock();
    // destroy(root);
    // cout << "destroy time : " << clock() - rec << " ms ";
    root = NULL;
}
SIZE : 100000 RUNTIME : 61 ms
SIZE : 100000 RUNTIME : 64 ms
SIZE : 100000 RUNTIME : 71 ms
SIZE : 100000 RUNTIME : 67 ms
SIZE : 100000 RUNTIME : 65 ms

可以确定是清空操作(destroy)造成了这一现象。此时我陷入了疑惑:RUNTIME所记录的仅仅是执行红黑树“插入”操作所消耗的时间,并没有记录清空操作的时间,与清空操作唯一的联系是对于内存的操作。但清空操作完成后,此时红黑树的根结点指针指向空结点,整个程序的执行状态和程序刚开始时几乎完全相同,但实际运行时间却差了40-50倍。

一个猜想是清空时的delete操作影响到了程序所能够使用的内存空间,但delete是起到回收内存的作用的,理论上来说意味着可供使用的内存空间更大了,为什么会比不回收内存空间的写法耗时更久呢?这一猜想完全不能解释这种现象。

以上就是我目前遇到的最主要的问题,对此我还做了以下尝试:

  1. 修改测试数据规模大小,测试了10^6的情况,仍有这个问题

    destroy time : 0 ms SIZE : 1000000 RUNTIME : 669 ms
    destroy time : 470 ms SIZE : 1000000 RUNTIME : 7070 ms
    destroy time : 462 ms SIZE : 1000000 RUNTIME : 7294 ms
    destroy time : 473 ms SIZE : 1000000 RUNTIME : 7754 ms
    destroy time : 471 ms SIZE : 1000000 RUNTIME : 6117 ms
    destroy time : 468 ms
    
  2. 把释放内存的部分写到了RBTNode的析构函数中,并修改对应的destroy:

    class RBTNode {
         
    public:
        RBTColor color;
        int key;
        RBTNode *lson;
        RBTNode *rson;
        RBTNode *parent;
        RBTNode(RBTColor c, int k) {
         
            color = c;
            key = k;
            lson = rson = parent = NULL;
        }
        ~RBTNode() {
         
            if (lson) delete(lson); lson = NULL;
            if (rson) delete(rson); rson = NULL;
        }
    };
    void destroy() {
         
        clock_t rec = clock();
        delete(root);
        root = NULL;
        cout << "destroy time : " << clock() - rec << " ms ";
    }
    

    从结果来说,和原来的没有任何区别

  3. 写了一个简化版的测试程序,通过最简单的数据结构(链表)进行测试,问题仍然存在,可见不是红黑树操作的问题

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int cnt;
    
    class Node {
         
    public:
        Node(int x) {
         
            key = x;
            nxt = NULL;
        }
        int key;
        Node *nxt;
    }
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值