Algorithm improvements, free_unreachable_objects() added.

[SVN r16894]
This commit is contained in:
Peter Dimov
2003-01-13 17:11:28 +00:00
parent 8eaf187dbd
commit 78a47d7619

View File

@@ -14,11 +14,12 @@
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS) #if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/detail/shared_count.hpp> #include <boost/shared_ptr.hpp>
#include <boost/detail/lightweight_mutex.hpp> #include <boost/detail/lightweight_mutex.hpp>
#include <new> #include <new>
#include <cstdlib> #include <cstdlib>
#include <map> #include <map>
#include <deque>
#include <iostream> #include <iostream>
int const m = 2; // m * sizeof(int) must be aligned appropriately 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 // 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() static map_type & get_map()
{ {
@@ -151,7 +152,9 @@ namespace
// assume 4 byte alignment for pointers when scanning // assume 4 byte alignment for pointers when scanning
size_t const pointer_align = 4; 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); 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); 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) 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); 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 open.push_back(q->pn.pi);
m2.erase(q->pn.pi);
if(m2[q->pn.pi] != 0)
{
updated = true;
m2[q->pn.pi] = 0;
}
} }
} }
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 // 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 // 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); 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);
if(p->use_count() != m2[p] && scan_and_mark(i->second.first, i->second.second, m, m2))
{
updated = true;
}
} }
} while(updated); for(open_type::iterator j = open.begin(); j != open.end(); ++j)
// 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])
{ {
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);
} }
} }