3

我对在 C++ 中使用指针/智能指针感到困惑。我们想从 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 中的一个愚蠢的 SPMC队列中。当队列满时,被写入一个名为_buffersConnection 的链表。

捕获工作正常,我们保存所有数据包。我们对这种代码和平的问题是它的高内存消耗。当打包到达时,activeBufferConnection 将其存储。当数据包数量增加到 1000000 时,会创建新的 activeBufferConnection 并将最后一个存储在名为 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 个元素。这是我们在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 的第一个循环将数据包存储在一些缓冲区中。在第二个循环中删除缓冲区后,它们使用的内存没有被释放,我们不知道为什么会发生这种情况。

                    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

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

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

我们怎样才能解决这个问题?提前致谢。

4

0 回答 0