|
From: Nir T. <nir...@gm...> - 2009-11-30 05:33:30
|
On Sun, Nov 29, 2009 at 9:06 PM, John Reiser <jr...@bi...> wrote:
>> ... any way to report all the locations
>> where memory is allocated. ...
>
> A static list of all the locations that _can_ allocate memory
> is useful, especially for an embedded environment ("If any location
> _can_ allocate memory, then eventually it _will_, often when memory
> is least available.")
>
> A pipeline such as this will identify all the compilation units
> with calls to alloc or new:
> nm -gop $(find . -name '*.[oa]') | grep -E 'alloc|new'
>
> A pipeline such as this will identify the locations of calls
> to alloc or new:
> readelf --relocs $(find . -name '*.o') | grep -E 'alloc|new'
>
> You may wish to insert " | c++filt " into the pipeline
> to demangle subroutine names. Also 'addr2line' can help
> identify line numbers.
This is a great suggestion, and will work spectacularly for plain C
code. However, for C++ code, you will generally need the entire call
graph to understand where the allocation comes from. Consider the
following simple example:
#include <iostream>
#include <vector>
std::vector<int> goo()
{
std::vector<int> vec;
vec.push_back(1);
return vec;
}
int main()
{
std::vector<int> vec = goo();
std::cout << vec.front() << std::endl;
return 0;
}
and then:
> nm -gop test | grep -E 'alloc|new' | c++filt
test:000000000040107c W
__gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long)
test:0000000000400da8 W __gnu_cxx::new_allocator<int>::~new_allocator()
test:000000000040109c W std::_Vector_base<int, std::allocator<int>
>::_M_deallocate(int*, unsigned long)
test:0000000000400e48 W std::_Vector_base<int, std::allocator<int>
>::_M_get_Tp_allocator()
test:0000000000400de2 W
__gnu_cxx::new_allocator<int>::new_allocator(__gnu_cxx::new_allocator<int>
const&)
test: U std::__throw_bad_alloc()@@GLIBCXX_3.4
test:0000000000400ebc W std::_Vector_base<int, std::allocator<int>
>::_M_get_Tp_allocator() const
test:0000000000400e56 W __gnu_cxx::new_allocator<int>::construct(int*,
int const&)
test:0000000000401406 W std::_Vector_base<int, std::allocator<int>
>::_M_allocate(unsigned long)
test:0000000000401048 W __gnu_cxx::new_allocator<int>::max_size() const
test:00000000004013bc W
__gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*)
test:0000000000400d86 W __gnu_cxx::new_allocator<int>::new_allocator()
not much info there, except that some allocations are related to
vectors. And believe me, when you start using some of the frameworks
in boost, you will be at a total loss, especially if the code you are
inspecting is not your own...
Your point of view can also be applied as to why do we need callgrind,
when we can perform a static analysis of our code, which will give us
the same results? Because it is much harder to do so (and even
impossible in some cases).
Cheers,
Nir.
|