我正在研究一段代码,其目标是成为一个快速的“搜索引擎”。我在一个文件中有条目,需要在读取整个文件后进行搜索。它们需要可以通过条目的名称进行搜索,并且它从文件的开头偏移。我的问题是内存使用问题,因为有数百万条目。目前我使用两个单独的std :: maps来存储数据,以便可以指定任一搜索项。这导致数据的双重存储,这正是我试图减少的。
我使用valgrind massif发现内存使用的主要部分是条目的双重存储。
目前的储存方法:
struct entry {
std::string name;
uint16_t offset;
uint16_t size;
bool isConst;
};
nameSearchMap.insert(std::pair<std::string, entry>(s_entry.name, e_entry));
offsetSearchMap.insert(std::pair<uint16_t, SymInfo>(s_entry.offset, s_entry));
有没有办法让我可以制作一个可以通过任何一种键搜索的地图?
答案 0 :(得分:5)
您可以考虑使用
std::map<std::string, std::shared_ptr<entry>>
用于将字符串映射到条目,以及
std::map<uint16_t, std::shared_ptr<entry>>
请注意,通过使用值有效负载的共享指针(因此对两个映射使用相同的entry
对象),可以保存有效负载的大小。虽然您需要支付两个共享指针,但您仍然可以提前确定具体结构。
(感觉就像绘制图表。但重点是内存中只有一个entry
对象。)
您可能也对boost::bimap
感兴趣。
答案 1 :(得分:2)
它们需要通过条目名称和文件开头的偏移量进行搜索。
这向我表明,您可以将数据存储在数组/向量中,并使用映射到数组/向量中的索引的映射。
std::vector<entry> entries;
std::map<std::string, size_t> map1;
std::map<uint16_t, size_t> map2;
答案 2 :(得分:0)
每个条目可以节省三个poiner,并避免条目重复。但是只有在插入不是fetch时才可用的方法:
std:vector<std::string> names;
std:vector<entry> entries;
std:map<uint16_t,size_t> offset2pos;
名称和条目必须以相同的方式排序,所以 名称相等的pos分别具有该名称
names[pos] == entries[pos].name
和map offset2pos可以将偏移量转换为pos
size_t pos = offset2pos[offset]
将名称转换为pos使用二进制搜索(std :: lower_bound)
size_t pos = names.begin() - std::lower_bound( names.begin(), names.end(), offset )
这种技术适用于插入的频率不是fetch的情况。 但算法并非如此微不足道,你需要重新分配offset2pos(可能 每次插入一个或多个元素时重建。
在上面的答案中你需要为每个元素保存:
std :: string,uint16_t,2 * Sptr,4 * Mptr
在我的approuch中:
std :: string,uint16_t,Sptr,2 * Mptr
其中: Sptr - 是smaprt指针对象的内部指针 Mptr - 映射二进制三节点左右指针
每个条目3个指针就是你的记忆利润。
答案 3 :(得分:0)
您可以按如下方式使用Boost.MultiIndex:
<强> Live Coliru Demo 强>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <cstdint>
#include <string>
struct entry {
std::string name;
uint16_t offset;
uint16_t size;
bool isConst;
};
using namespace boost::multi_index;
using entry_map=multi_index_container<
entry,
indexed_by<
hashed_unique<tag<struct by_name>,member<entry,std::string,&entry::name>>,
hashed_unique<tag<struct by_offset>,member<entry,uint16_t,&entry::offset>>
>
>;
#include <iostream>
int main()
{
entry_map m={{"hello",0,10,false},{"hi",1,20,true},{"bye",2,15,false}};
auto& name_map=m.get<by_name>();
auto& offset_map=m.get<by_offset>();
std::cout<<"size(\"hello\"): "<<name_map.find("hello")->size<<"\n";
std::cout<<"size(2): "<<offset_map.find(2)->size<<"\n";
}
输出:
size("hello"): 10 size(2): 15