mirror of
https://github.com/boostorg/smart_ptr.git
synced 2025-07-31 21:24:40 +02:00
Algorithm improvements, free_unreachable_objects() added.
[SVN r16894]
This commit is contained in:
@@ -14,11 +14,12 @@
|
||||
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/shared_count.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/detail/lightweight_mutex.hpp>
|
||||
#include <new>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
|
||||
int const m = 2; // m * sizeof(int) must be aligned appropriately
|
||||
@@ -113,7 +114,7 @@ void * operator new[](size_t n, nothrow_t const &) throw()
|
||||
|
||||
// cycle detection
|
||||
|
||||
typedef std::map< void *, std::pair<void *, size_t> > map_type;
|
||||
typedef std::map< void const *, std::pair<void *, size_t> > map_type;
|
||||
|
||||
static map_type & get_map()
|
||||
{
|
||||
@@ -151,7 +152,9 @@ namespace
|
||||
// assume 4 byte alignment for pointers when scanning
|
||||
size_t const pointer_align = 4;
|
||||
|
||||
static void scan_and_count(void const * area, size_t size, map_type const & m, std::map<void const *, long> & m2)
|
||||
typedef std::map<void const *, long> map2_type;
|
||||
|
||||
static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2)
|
||||
{
|
||||
unsigned char const * p = static_cast<unsigned char const *>(area);
|
||||
|
||||
@@ -166,79 +169,132 @@ static void scan_and_count(void const * area, size_t size, map_type const & m, s
|
||||
}
|
||||
}
|
||||
|
||||
static bool scan_and_mark(void const * area, size_t size, map_type const & m, std::map<void const *, long> & m2)
|
||||
typedef std::deque<void const *> open_type;
|
||||
|
||||
static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
|
||||
{
|
||||
bool updated = false;
|
||||
unsigned char const * p = static_cast<unsigned char const *>(area);
|
||||
|
||||
for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
|
||||
{
|
||||
shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
|
||||
|
||||
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
|
||||
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0)
|
||||
{
|
||||
// mark as reachable
|
||||
|
||||
if(m2[q->pn.pi] != 0)
|
||||
{
|
||||
updated = true;
|
||||
m2[q->pn.pi] = 0;
|
||||
}
|
||||
open.push_back(q->pn.pi);
|
||||
m2.erase(q->pn.pi);
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
void report_unreachable_objects()
|
||||
static void find_unreachable_objects(map_type const & m, map2_type & m2)
|
||||
{
|
||||
std::map<void const *, long> m2;
|
||||
|
||||
mutex_type::scoped_lock lock(get_mutex());
|
||||
|
||||
map_type & m = get_map();
|
||||
|
||||
// scan objects for shared_ptr members, compute internal counts
|
||||
|
||||
for(map_type::iterator i = m.begin(); i != m.end(); ++i)
|
||||
{
|
||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base *>(i->first);
|
||||
for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
|
||||
{
|
||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base const *>(i->first);
|
||||
|
||||
BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map
|
||||
BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map
|
||||
|
||||
scan_and_count(i->second.first, i->second.second, m, m2);
|
||||
scan_and_count(i->second.first, i->second.second, m, m2);
|
||||
}
|
||||
}
|
||||
|
||||
// mark reachable objects
|
||||
|
||||
bool updated;
|
||||
|
||||
do
|
||||
{
|
||||
updated = false;
|
||||
open_type open;
|
||||
|
||||
for(map_type::iterator i = m.begin(); i != m.end(); ++i)
|
||||
for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
|
||||
{
|
||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base *>(i->first);
|
||||
|
||||
if(p->use_count() != m2[p] && scan_and_mark(i->second.first, i->second.second, m, m2))
|
||||
{
|
||||
updated = true;
|
||||
}
|
||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base const *>(i->first);
|
||||
if(p->use_count() != i->second) open.push_back(p);
|
||||
}
|
||||
|
||||
} while(updated);
|
||||
|
||||
// report unreachable objects
|
||||
|
||||
for(map_type::iterator i = m.begin(); i != m.end(); ++i)
|
||||
{
|
||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base *>(i->first);
|
||||
|
||||
if(p->use_count() == m2[p])
|
||||
for(open_type::iterator j = open.begin(); j != open.end(); ++j)
|
||||
{
|
||||
std::cerr << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
|
||||
m2.erase(*j);
|
||||
}
|
||||
|
||||
while(!open.empty())
|
||||
{
|
||||
void const * p = open.front();
|
||||
open.pop_front();
|
||||
|
||||
map_type::const_iterator i = m.find(p);
|
||||
BOOST_ASSERT(i != m.end());
|
||||
|
||||
scan_and_mark(i->second.first, i->second.second, m2, open);
|
||||
}
|
||||
}
|
||||
|
||||
// m2 now contains the unreachable objects
|
||||
}
|
||||
|
||||
void report_unreachable_objects(bool verbose)
|
||||
{
|
||||
map2_type m2;
|
||||
|
||||
mutex_type::scoped_lock lock(get_mutex());
|
||||
|
||||
map_type const & m = get_map();
|
||||
|
||||
find_unreachable_objects(m, m2);
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
|
||||
{
|
||||
map_type::const_iterator i = m.find(j->first);
|
||||
BOOST_ASSERT(i != m.end());
|
||||
// std::cerr << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(verbose || !m2.empty())
|
||||
{
|
||||
std::cerr << m2.size() << " unreachable objects.\n";
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::deque< boost::shared_ptr<X> > free_list_type;
|
||||
|
||||
static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free)
|
||||
{
|
||||
unsigned char * p = static_cast<unsigned char *>(area);
|
||||
|
||||
for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
|
||||
{
|
||||
shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p);
|
||||
|
||||
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
|
||||
{
|
||||
boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p);
|
||||
free.push_back(*ppx);
|
||||
ppx->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void free_unreachable_objects()
|
||||
{
|
||||
map2_type m2;
|
||||
|
||||
mutex_type::scoped_lock lock(get_mutex());
|
||||
|
||||
map_type const & m = get_map();
|
||||
|
||||
find_unreachable_objects(m, m2);
|
||||
|
||||
free_list_type free;
|
||||
|
||||
for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
|
||||
{
|
||||
map_type::const_iterator i = m.find(j->first);
|
||||
BOOST_ASSERT(i != m.end());
|
||||
scan_and_free(i->second.first, i->second.second, m2, free);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user