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)
#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);
}
}