我需要在程序中收集有关内存使用情况的统计信息。
我的代码主要使用STL编写。
有没有办法了解STL对象消耗了多少内存?
例如,
string s1 = "hello";
string s2 = "hellohellohellohellohellohellohellohellohellohellohellohellohello";
s1
和s2
消耗了多少内存?
显然,sizeof(string)+s1.length()
不太准确。
答案 0 :(得分:15)
如果您愿意稍微介入一下,可以创建一个自定义分配器来按容器类型或已分配的类型跟踪所有堆使用情况。这非常具有侵入性,但也非常准确,用于确定内存使用情况。这不会跟踪堆本身占用多少内存,因为这是高度依赖于操作系统的。
template<class TrackType>
size_t* mem_used() {static size_t s = 0; return &s;}
template<class T, class TrackType, class BaseAllocator = std::allocator<T> >
class TrackerAllocator : public BaseAllocator {
public:
typedef typename BaseAllocator::pointer pointer;
typedef typename BaseAllocator::size_type size_type;
TrackerAllocator() throw() : BaseAllocator() {}
TrackerAllocator(const TrackerAllocator& b) throw() : BaseAllocator(b) {}
TrackerAllocator(TrackerAllocator&& b) throw() : BaseAllocator(b) {}
template <class U> TrackerAllocator(const typename TrackerAllocator::template rebind<U>::other& b) throw() : BaseAllocator(b) {}
~TrackerAllocator() {}
template<class U> struct rebind {
typedef TrackerAllocator<U, TrackType, typename BaseAllocator::template rebind<U>::other> other;
};
pointer allocate(size_type n) {
pointer r = BaseAllocator::allocate(n);
*mem_used<TrackType>() += n;
return r;
}
pointer allocate(size_type n, pointer h) {
pointer r = BaseAllocator::allocate(n, h);
*mem_used<TrackType>() += n;
return r;
}
void deallocate(pointer p, size_type n) throw() {
BaseAllocator::deallocate(p, n);
*mem_used<TrackType>() -= n;
}
};
用法是:
typedef std::basic_string<char,
std::char_traits<char>,
TrackerAllocator<char, std::string> > trackstring;
typedef std::vector<int,
TrackerAllocator<int, std::vector<int> > > trackvector;
// ^ ^
// This identifies which memory to track
// it can be any type, related or no.
// All with the same type will be tracked togeather
int main() {
trackstring mystring1("HELLO WORLD");
std::cout << *mem_used<std::string>() << '\n'; //display memory usage of all strings
trackstring mystring2("MUCH LONGER STRING THAT DEFINITELY GETS HEAP ALLOCATED!");
std::cout << *mem_used<std::string>() << '\n'; //display memory usage of all strings
trackvector myvec(mystring1.begin(), mystring1.end());
std::cout << *mem_used<std::vector<int> >() << '\n'; //display memory usage of all vector<int>
// ^ ^
// This identifies which memory type from above to look up.
return 0;
}
Windows结果:
0 //这是零,因为字符串没有分配堆空间 64个
11
http://ideone.com/lr4I8(GCC)结果:
24
92个
11
答案 1 :(得分:5)
由于这完全是实施细节,因此无法通过100%
准确度来确定。
但是,正如您所说,您希望在程序中添加一些代码来统计内存使用情况,然后您可以准确地执行此操作。
我相信,对于std::string
,字符串对象占用的内存大小将几乎等于:
size_t statisticalSizeStr = sizeof(string)+ s.capacity() * sizeof(char);
同样地,对于std::vector
size_t statisticalSizeVec = sizeof(std::vector<T>)+ ....;
您可以对此类信息进行统计估算建模。对于矢量,您还可以考虑T
的大小,其方式将填充上述等式中的....
。例如,如果T
为std::string
,则为:
size_t vecSize = sizeof(std::vector<std::string>);
size_t statisticalSizeVec = vecSize + v.capacity() * statisticalSizeStr;
如果T
是int
,那么
size_t statisticalSizeVec=sizeof(std::vector<int>)+v.capacity()*sizeof(int);
我希望,这样的分析可以帮助您尽可能准确地计算尺寸。
答案 2 :(得分:3)
为了好玩,我尽最大努力找到你给出的单个字符串的内存使用情况。我同意那些说基本上不可能的人;我的实施在很多方面都不好:
#define private public
告诉我我“做错了”并且取决于不仅没有标准化的东西,甚至我的STL实现(gcc 4.6)可能会在下一个版本中改变。你永远不应该在生产代码中看到这一点。std::string
。您必须为每种类型执行特定逻辑,因为我的平台上不存在任何通用机制。对于容器,你必须递归; O(1)
get_allocated_size()
malloc_usable_size
来查看malloc返回的区域的实际大小。首先,这特定于glibc
中包含的分配器。其次,它不计算malloc的簿记记忆。第三,这种分配可能会导致其他一些分配占用更多内存,因为它会在虚拟地址空间中引入碎片或其他类型。但它比调用者要求的更准确,因为malloc倾向于将事情弄清楚。在实践中,我建议将Nawaz提及的近似值与其他人提到的全过程测量结果进行经验验证。
话虽如此,我们走了:
$ cat > sizetest.cc <<EOF
#define private public // eww...
#include <malloc.h>
#include <iostream>
#include <string>
using namespace std;
// NON-PORTABLE! Totally dependent on gcc 4.6 / glibc (with the stock allocator)!
size_t get_size(const string &s) {
string::_Rep *rep = (string::_Rep*) s.data() - 1;
return sizeof(string) + malloc_usable_size(rep);
}
int main(int argc, char **argv) {
string s1 = "hello";
string s2 = "hellohellohellohellohellohellohellohellohellohellohellohellohello";
cout << "s1 size: " << get_size(s1) << endl;
cout << "s2 size: " << get_size(s2) << endl;
return 0;
}
EOF
$ g++ -Wall sizetest.cc -o sizetest
$ ./sizetest
s1 size: 48
s2 size: 112
答案 3 :(得分:2)
我认为不可能测量单个容器。
但是,要获得总体摘要,可以使用mallinfo()函数(在Linux上)。
如果你想知道你的程序中最大的内存耗尽在哪里,你可以在valgrind下使用massif memory profiler运行它,这将为你提供“从map<my_data>::...
分配的15 MB”等信息。 ,你可以猜出你的结构有多大。
答案 4 :(得分:1)
如果您想要一般内存使用统计信息,可以使用Psapi。
#ifdef WIN32
#include <psapi.h>
#elif __GNUC__
#include <sys/time.h>
#include <sys/resource.h>
#endif
void MemoryUsage()
{
#ifdef WIN32
PROCESS_MEMORY_COUNTERS pmc;
if(GetProcessMemoryInfo(GetCurrentProcess(),&pmc,sizeof(pmc)))
{
// do something with the values you care about
pmc.PagefileUsage;
pmc.PeakPagefileUsage;
pmc.PeakWorkingSetSize;
pmc.QuotaNonPagedPoolUsage;
pmc.QuotaPagedPoolUsage;
pmc.QuotaPeakNonPagedPoolUsage;
pmc.WorkingSetSize;
}
#else
// I'm not a penguin
#endif
}