使用智能指针c ++实现高内存消耗

时间:2016-10-18 10:04:58

标签: c++ memory-management memory-leaks smart-pointers memory-consumption

我对在c ++中使用指针/ smartpointer感到困惑。 我们想从NIC捕获数据包。我们使用PF_RING ZC来捕获数据包,如下所示:

typedef folly::ProducerConsumerQueue<std::string> ZCTask;
typedef boost::shared_ptr<ZCTask> ZCTask_ptr;

void runZCConnection() {
        ZCTask_ptr activeBufferConnection(new folly::ProducerConsumerQueue<std::string>(200000));
        LOG_INFO("capture_loop for connections: Entering >> SHARE POINTER .");
            int h = 0;
        for (;;) {
            if (likely(pfring_zc_recv_pkt(zqc, &buffer_connection, _wait_for_packet) >= 0)) {
                u_char *pkt_data = pfring_zc_pkt_buff_data(buffer_connection, zqc);
                std::string payload(pkt_data + _ConnectionHeaderSize, pkt_data + _snapLengthConnection); 

                if (activeBufferConnection->isFull()) {
                    LOG_INFO("ZC Active buffer Connction is full");
                    _buffersConnection.add(activeBufferConnection);
                    LOG_INFO(">> after add. USAGEG   %ld", activeBufferConnection.use_count());
                    activeBufferConnection.reset(new folly::ProducerConsumerQueue<std::string>(200000));
                    LOG_INFO(">> after reset. USAGEG   %ld", activeBufferConnection.use_count());
folly::ProducerConsumerQueue<std::string>(_bufferSizeConnection + 1);
                    if (h++ > 25) {
                        break;
                    }

                }
                activeBufferConnection->write(payload);
                continue;
            }
        }

for (int a = 0; a < 25; a++) {
            //get new task                                   
            Node* node = _buffersConnection.get2();
            {
                ZCTask_ptr zcTaskConnection = node->Data;
                delete node;
                node = NULL;
                LOG_INFO(">> After node delete. USAGEG   %ld", 
                LOG_INFO("connection buffer : %d", a);

            }
        }
        LOG_INFO("delete");
    } //packet consumer

可以看出,首先我们将数据包存储在runZCWrapper中的folly SPMC队列中。当队列已满时,将写入名为_ buffersConnection的链接列表。

捕获工作正常,我们保存所有数据包。这种代码和平的问题在于它的高内存消耗。当打包到达时,activeBufferConnection会存储它。当数据包数量增加到1000000时,创建新的activeBufferConnection并将最后一个存储在名为buffersconnections的链接列表中。我们将buffersconnections的数量设置为25。

从上面的代码和平中可以看出,我们正在使用智能指针 指向activeBufferConnection。当activeBufferConnection已满时,其指针传递给buffersconnections的“add”方法。

以下是我们在runZCConnection中使用的ArchiveList类的一些代码;

class ArchiveList {
    typedef folly::ProducerConsumerQueue<std::string> ZCTask;
    typedef boost::shared_ptr<ZCTask> ZCTask_ptr;
private:
    Node* root;Node* last;    
    std::mutex mutex_;
    std::condition_variable cond_;
public:

    ArchiveList() {
        root = new Node();
        last = root;
    }

    Node*
    get2() {
        std::unique_lock<std::mutex> mlock(mutex_);
        while (root->Next == NULL) {
            LOG_INFO("get null");
            cond_.wait(mlock);
        }
        LOG_INFO("1");
        Node* toDelete = root->Next;
        LOG_INFO("1");
        root->Next = toDelete->Next;
        LOG_INFO("1");
        return toDelete;
    }

    void
    add(ZCTask_ptr item) {
        std::unique_lock<std::mutex> mlock(mutex_);
        Node* newItem = new Node();
        newItem->Data = item;
        newItem->Prev = last;
        last->Next = newItem;
        last = newItem;

        mlock.unlock();
        cond_.notify_one();
        LOG_INFO("+");
    }

};

当activeBufferConnection的数量增加到25时,第一个循环结束,第二个循环开始工作。第二个循环删除链接列表的所有25个元素。 以下是我们的Node类的一些代码,用于runZCConnection;

class Node {
public:
    typedef folly::ProducerConsumerQueue<std::string> ZCTask;
    typedef boost::shared_ptr<ZCTask> ZCTask_ptr;

    Node() {
        Next = NULL;Prev = NULL;Data = NULL;
    }

    ~Node() {
        Next = NULL;Prev = NULL;
        LOG_INFO(" >> NODE DCTOR. USAGEG   %ld", Data.use_count());
        Data.reset();
        LOG_INFO("NODE DCTOR");
    }

    ZCTask_ptr Data;
    Node* Next;
    Node* Prev;
private:    
};

top命令的输出是问题所在。 runZCConnection的第一个循环在一些缓冲区上存储数据包。删除其secound循环上的缓冲区后,它们使用的内存不会被释放,我们不知道为什么会发生这种情况。

                    CPU     MEM
 83698 root         49.3    0.3      0:01.49 ng4-m2
 83698 root         39.1    0.6     0:02.67 ng4-m2
 83698 root         41.5    0.8     0:03.92 ng4-m2
 83698 root         1.3     1.0     0:05.49 ng4-m2
 83698 root         1.0     1.0      0:05.52 ng4-m2
 83698 root         1.7     0.9     0:05.57 ng4-m2

如上面的命令所示,程序删除所有缓冲区后,内存不会被释放。问题可能与错误删除缓冲区有关,也可能与错误使用指针有关。我们在代码的某些位置设置了一些日志,这些日志返回有关程序及其指针状态的一些信息。 以下是一些输出行:

INFO    | ZCWrapper.hpp   | runZCConnection:260 : ZC Active buffer Connction is full
INFO    | ArchiveList.h   | add:80 : +
INFO    | ZCWrapper.hpp   | runZCConnection:262 : >> after add. USAGEG   2
INFO    | ZCWrapper.hpp   | runZCConnection:264 : >> after reset. USAGEG   1
.
.
.
INFO    | ArchiveList.h   | get2:56 : 1
INFO    | Node.hpp        | ~Node:27 :  >> NODE DCTOR. USAGEG   2
INFO    | Node.hpp        | ~Node:29 : NODE DCTOR
INFO    | ZCWrapper.hpp   | runZCConnection:286 : >> After node delete. USAGEG   1
INFO    | ZCWrapper.hpp   | runZCConnection:308 : >> END OF ONE TASK. USAGEG   0
INFO    | ZCWrapper.hpp   | runZCConnection:310 : connection buffer : 1
.
.
.
INFO    | ZCWrapper.hpp   | runZCConnection:315 : delete

我们如何解决问题? 在此先感谢。

0 个答案:

没有答案