我怎么知道STL对象需要多少内存?

时间:2011-09-16 17:51:23

标签: c++ memory stl

我需要在程序中收集有关内存使用情况的统计信息。

我的代码主要使用STL编写。

有没有办法了解STL对象消耗了多少内存?

例如,

string s1 = "hello";
string s2 = "hellohellohellohellohellohellohellohellohellohellohellohellohello";

s1s2消耗了多少内存? 显然,sizeof(string)+s1.length()不太准确。

5 个答案:

答案 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的大小,其方式将填充上述等式中的....。例如,如果Tstd::string,则为:

size_t vecSize = sizeof(std::vector<std::string>);
size_t statisticalSizeVec = vecSize  + v.capacity() * statisticalSizeStr;

如果Tint,那么

size_t statisticalSizeVec=sizeof(std::vector<int>)+v.capacity()*sizeof(int);

我希望,这样的分析可以帮助您尽可能准确地计算尺寸。

答案 2 :(得分:3)

为了好玩,我尽最大努力找到你给出的单个字符串的内存使用情况。我同意那些说基本上不可能的人;我的实施在很多方面都不好:

  • #define private public告诉我我“做错了”并且取决于不仅没有标准化的东西,甚至我的STL实现(gcc 4.6)可能会在下一个版本中改变。你永远不应该在生产代码中看到这一点。
  • 我认为你正在寻找可用于任何STL对象的东西,我只实现了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
}
相关问题