如何优化字符串复制(内存分配)?

时间:2011-09-19 23:40:34

标签: c++ string visual-studio-2008 visual-c++ stl

我正在制作一个程序(想想:Launchy之类的东西)或多或少地通过一堆字符串并根据某些标准对它们进行排名。

我将结果存储在vector<SearchSuggestion>中,其中结构当前定义如下:

struct SearchSuggestion
{
    std::string path;
    int tag;
};

在我的程序中,由于需要操作大量的文件路径等等,我会将结构(以及字符串)复制很多。

虽然这会在释放模式中引起明显但很小的延迟,但显着会减慢程序的调试速度(即按键之间的几秒钟暂停)。寻找原因,我发现几乎所有的时间都花在了下面的堆栈跟踪上:

ntdll.dll!RtlCompareMemoryUlong()   
ntdll.dll!RtlpAllocateHeap()    
ntdll.dll!RtlAllocateHeap()     
ntdll.dll!RtlDebugAllocateHeap()    
ntdll.dll!string "Enabling heap debug options\n"()  
ntdll.dll!RtlAllocateHeap()     
msvcr90d.dll!_heap_alloc_base(unsigned __int64)     C
msvcr90d.dll!_heap_alloc_dbg_impl(unsigned __int64, int, const char *, int, int *)
msvcr90d.dll!_nh_malloc_dbg_impl(unsigned __int64, int, int, const char *, int, int *)
msvcr90d.dll!_nh_malloc_dbg(unsigned __int64, int, int, const char *, int)
msvcr90d.dll!malloc(unsigned __int64)
msvcr90d.dll!operator new(unsigned __int64)
MyProgram.exe!std::_Allocate<wchar_t>(unsigned __int64, wchar_t *)
MyProgram.exe!std::allocator<wchar_t>::allocate(unsigned __int64)
MyProgram.exe!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::_Copy(unsigned __int64, unsigned __int64)
MyProgram.exe!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::_Grow(unsigned __int64, bool)
MyProgram.exe!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::assign(const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > &, unsigned __int64, unsigned __int64)
MyProgram.exe!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >(const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > &)
MyProgram.exe!SearchSuggestion::SearchSuggestion(const SearchSuggestion &)
MyProgram.exe!std::_Construct<SearchSuggestion,SearchSuggestion>(SearchSuggestion *, const SearchSuggestion &)
MyProgram.exe!std::allocator<SearchSuggestion>::construct(SearchSuggestion *, const SearchSuggestion &)
MyProgram.exe!std::_Uninit_copy<SearchSuggestion * __ptr64,SearchSuggestion * __ptr64,std::allocator<SearchSuggestion> >(SearchSuggestion *, SearchSuggestion *, SearchSuggestion *, std::allocator<SearchSuggestion> &, std::_Nonscalar_ptr_iterator_tag, std::_Nonscalar_ptr_iterator_tag)
MyProgram.exe!stdext::unchecked_uninitialized_copy<SearchSuggestion * __ptr64,SearchSuggestion * __ptr64,std::allocator<SearchSuggestion> >(SearchSuggestion *, SearchSuggestion *, SearchSuggestion *, std::allocator<SearchSuggestion> &)
MyProgram.exe!std::_Uninit_move<SearchSuggestion * __ptr64,SearchSuggestion * __ptr64,std::allocator<SearchSuggestion>,std::_Undefined_move_tag>(SearchSuggestion *, SearchSuggestion *, SearchSuggestion *, std::allocator<SearchSuggestion> &, std::_Undefined_move_tag, std::_Undefined_move_tag)
MyProgram.exe!stdext::_Unchecked_uninitialized_move<SearchSuggestion * __ptr64,SearchSuggestion * __ptr64,std::allocator<SearchSuggestion> >(SearchSuggestion *, SearchSuggestion *, SearchSuggestion *, std::allocator<SearchSuggestion> &)
MyProgram.exe!std::vector<SearchSuggestion,std::allocator<SearchSuggestion> >::_Umove<SearchSuggestion * __ptr64>(SearchSuggestion *, SearchSuggestion *, SearchSuggestion *)
MyProgram.exe!std::vector<SearchSuggestion,std::allocator<SearchSuggestion> >::_Insert_n(std::_Vector_const_iterator<SearchSuggestion,std::allocator<SearchSuggestion> > *, unsigned __int64, const SearchSuggestion &)
MyProgram.exe!std::vector<SearchSuggestion,std::allocator<SearchSuggestion> >::insert(std::_Vector_const_iterator<SearchSuggestion,std::allocator<SearchSuggestion> > *, const SearchSuggestion &)
MyProgram.exe!std::vector<SearchSuggestion,std::allocator<SearchSuggestion> >::push_back(const SearchSuggestion &)
MyProgram.exe!Appender<std::vector<SearchSuggestion,std::allocator<SearchSuggestion> > >(const wchar_t *, _tfinddata *, void *)
MyProgram.exe!EnumMatches(const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > &, const std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > > > &, int (const wchar_t *, _tfinddata *, void *)*, void *, int)
...

所以很明显,复制std::string需要花费太长时间,可能是因为参考地点不佳。

所以现在我的问题很简单:

如何提高分配大量小字符串的性能?

4 个答案:

答案 0 :(得分:4)

一种方法是停止将它们按值放入SearchSuggestion结构中。而是为每个SearchSuggestion提供代表路径的std::string句柄。

struct SearchSuggestion {
  int pathId;
  int tag;
};

这将使向量内的复制更有效,因为它只是复制简单的int而不是复杂的std::string值。

然后,您可以使用std::map<int, std::string>结构将路径ID映射到实际路径中。

答案 1 :(得分:3)

您可以尝试使用Boost.Flyweight。我不保证它会起作用 - 不复制字符串所节省的时间可能用于检查该字符串是否尚未存储 - 但你可以尝试一下。

另一种选择是将其变为boost::shared_ptr<std::string>。现在只需要复制一个指针(因此成本几乎为空),但现在实际访问该字符串时会增加成本(但这可能不是一个大问题)。

尝试这两个并不难看哪一个产生更好的结果。

答案 2 :(得分:1)

最有效的答案是:不要分配和复制大量字符串。使用共享指针代替常量字符串或符号。

Malloc()和strcpy()只是慢,句号,复制字符串总是一个O(n)操作。在实时代码中,最好尽可能避免分配。

答案 3 :(得分:1)