mirror of
https://github.com/boostorg/smart_ptr.git
synced 2025-08-02 14:14:27 +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)
|
#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,80 +169,133 @@ 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))
|
for(open_type::iterator j = open.begin(); j != open.end(); ++j)
|
||||||
{
|
{
|
||||||
updated = true;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(updated);
|
// m2 now contains the unreachable objects
|
||||||
|
}
|
||||||
|
|
||||||
// report unreachable objects
|
void report_unreachable_objects(bool verbose)
|
||||||
|
{
|
||||||
|
map2_type m2;
|
||||||
|
|
||||||
for(map_type::iterator i = m.begin(); i != m.end(); ++i)
|
mutex_type::scoped_lock lock(get_mutex());
|
||||||
|
|
||||||
|
map_type const & m = get_map();
|
||||||
|
|
||||||
|
find_unreachable_objects(m, m2);
|
||||||
|
|
||||||
|
if(verbose)
|
||||||
{
|
{
|
||||||
boost::detail::counted_base const * p = static_cast<boost::detail::counted_base *>(i->first);
|
for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
|
||||||
|
|
||||||
if(p->use_count() == m2[p])
|
|
||||||
{
|
{
|
||||||
std::cerr << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug hooks
|
// debug hooks
|
||||||
|
Reference in New Issue
Block a user