我对在 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
我们怎样才能解决这个问题?提前致谢。