mirror of
https://github.com/boostorg/smart_ptr.git
synced 2025-08-01 05:34:36 +02:00
Moved 'garbage collector' to sp_collector.cpp, collector_test.cpp added.
[SVN r17050]
This commit is contained in:
@@ -355,6 +355,9 @@ public:
|
|||||||
~shared_count() // nothrow
|
~shared_count() // nothrow
|
||||||
{
|
{
|
||||||
if(pi_ != 0) pi_->release();
|
if(pi_ != 0) pi_->release();
|
||||||
|
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
||||||
|
id_ = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_count(shared_count const & r): pi_(r.pi_) // nothrow
|
shared_count(shared_count const & r): pi_(r.pi_) // nothrow
|
||||||
@@ -455,6 +458,9 @@ public:
|
|||||||
~weak_count() // nothrow
|
~weak_count() // nothrow
|
||||||
{
|
{
|
||||||
if(pi_ != 0) pi_->weak_release();
|
if(pi_ != 0) pi_->weak_release();
|
||||||
|
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
||||||
|
id_ = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
weak_count & operator= (shared_count const & r) // nothrow
|
weak_count & operator= (shared_count const & r) // nothrow
|
||||||
|
267
src/sp_collector.cpp
Normal file
267
src/sp_collector.cpp
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
//
|
||||||
|
// sp_collector.cpp
|
||||||
|
//
|
||||||
|
// Copyright (c) 2002, 2003 Peter Dimov
|
||||||
|
//
|
||||||
|
// Permission to copy, use, modify, sell and distribute this software
|
||||||
|
// is granted provided this copyright notice appears in all copies.
|
||||||
|
// This software is provided "as is" without express or implied
|
||||||
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <boost/detail/lightweight_mutex.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <map>
|
||||||
|
#include <deque>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef std::map< void const *, std::pair<void *, size_t> > map_type;
|
||||||
|
|
||||||
|
static map_type & get_map()
|
||||||
|
{
|
||||||
|
static map_type m;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef boost::detail::lightweight_mutex mutex_type;
|
||||||
|
|
||||||
|
static mutex_type & get_mutex()
|
||||||
|
{
|
||||||
|
static mutex_type m;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void * init_mutex_before_main = &get_mutex();
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class X;
|
||||||
|
|
||||||
|
struct count_layout
|
||||||
|
{
|
||||||
|
boost::detail::sp_counted_base * pi;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct shared_ptr_layout
|
||||||
|
{
|
||||||
|
X * px;
|
||||||
|
count_layout pn;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume 4 byte alignment for pointers when scanning
|
||||||
|
size_t const pointer_align = 4;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
++m2[q->pn.pi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::deque<void const *> open_type;
|
||||||
|
|
||||||
|
static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
|
||||||
|
{
|
||||||
|
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 && m2.count(q->pn.pi) != 0)
|
||||||
|
{
|
||||||
|
open.push_back(q->pn.pi);
|
||||||
|
m2.erase(q->pn.pi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_unreachable_objects_impl(map_type const & m, map2_type & m2)
|
||||||
|
{
|
||||||
|
// scan objects for shared_ptr members, compute internal counts
|
||||||
|
|
||||||
|
{
|
||||||
|
std::cout << "... " << m.size() << " objects in m.\n";
|
||||||
|
|
||||||
|
for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
|
||||||
|
{
|
||||||
|
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "... " << m2.size() << " objects in m2.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark reachable objects
|
||||||
|
|
||||||
|
{
|
||||||
|
open_type open;
|
||||||
|
|
||||||
|
for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
|
||||||
|
{
|
||||||
|
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
|
||||||
|
if(p->use_count() != i->second) open.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "... " << m2.size() << " objects in open.\n";
|
||||||
|
|
||||||
|
for(open_type::iterator j = open.begin(); j != open.end(); ++j)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t find_unreachable_objects(bool report)
|
||||||
|
{
|
||||||
|
map2_type m2;
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_THREADS
|
||||||
|
|
||||||
|
// This will work without the #ifdef, but some compilers warn
|
||||||
|
// that lock is not referenced
|
||||||
|
|
||||||
|
mutex_type::scoped_lock lock(get_mutex());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
map_type const & m = get_map();
|
||||||
|
|
||||||
|
find_unreachable_objects_impl(m, m2);
|
||||||
|
|
||||||
|
if(report)
|
||||||
|
{
|
||||||
|
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::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m2.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_THREADS
|
||||||
|
|
||||||
|
mutex_type::scoped_lock lock(get_mutex());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
map_type const & m = get_map();
|
||||||
|
|
||||||
|
find_unreachable_objects_impl(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "... about to free " << free.size() << " objects.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug hooks
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
|
||||||
|
void sp_scalar_constructor_hook(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
|
||||||
|
{
|
||||||
|
#ifdef BOOST_HAS_THREADS
|
||||||
|
|
||||||
|
mutex_type::scoped_lock lock(get_mutex());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
get_map()[pn] = std::make_pair(px, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_scalar_destructor_hook(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_scalar_destructor_hook(void *, std::size_t, void * pn)
|
||||||
|
{
|
||||||
|
#ifdef BOOST_HAS_THREADS
|
||||||
|
|
||||||
|
mutex_type::scoped_lock lock(get_mutex());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
get_map().erase(pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_array_constructor_hook(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_array_destructor_hook(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
@@ -8,19 +8,12 @@
|
|||||||
// This software is provided "as is" without express or implied
|
// This software is provided "as is" without express or implied
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
//
|
//
|
||||||
// http://www.boost.org/libs/smart_ptr/debug_hooks.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <boost/detail/lightweight_mutex.hpp>
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <map>
|
|
||||||
#include <deque>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int const m = 2; // m * sizeof(int) must be aligned appropriately
|
int const m = 2; // m * sizeof(int) must be aligned appropriately
|
||||||
|
|
||||||
@@ -112,192 +105,6 @@ void * operator new[](size_t n, nothrow_t const &) throw()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// cycle detection
|
|
||||||
|
|
||||||
typedef std::map< void const *, std::pair<void *, size_t> > map_type;
|
|
||||||
|
|
||||||
static map_type & get_map()
|
|
||||||
{
|
|
||||||
static map_type m;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef boost::detail::lightweight_mutex mutex_type;
|
|
||||||
|
|
||||||
static mutex_type & get_mutex()
|
|
||||||
{
|
|
||||||
static mutex_type m;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void * init_mutex_before_main = &get_mutex();
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class X;
|
|
||||||
|
|
||||||
struct count_layout
|
|
||||||
{
|
|
||||||
boost::detail::sp_counted_base * pi;
|
|
||||||
int id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct shared_ptr_layout
|
|
||||||
{
|
|
||||||
X * px;
|
|
||||||
count_layout pn;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume 4 byte alignment for pointers when scanning
|
|
||||||
size_t const pointer_align = 4;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
++m2[q->pn.pi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::deque<void const *> open_type;
|
|
||||||
|
|
||||||
static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
|
|
||||||
{
|
|
||||||
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 && m2.count(q->pn.pi) != 0)
|
|
||||||
{
|
|
||||||
open.push_back(q->pn.pi);
|
|
||||||
m2.erase(q->pn.pi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void find_unreachable_objects(map_type const & m, map2_type & m2)
|
|
||||||
{
|
|
||||||
// scan objects for shared_ptr members, compute internal counts
|
|
||||||
|
|
||||||
{
|
|
||||||
for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
|
|
||||||
{
|
|
||||||
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark reachable objects
|
|
||||||
|
|
||||||
{
|
|
||||||
open_type open;
|
|
||||||
|
|
||||||
for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
|
|
||||||
{
|
|
||||||
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
|
|
||||||
if(p->use_count() != i->second) open.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(open_type::iterator j = open.begin(); j != open.end(); ++j)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// debug hooks
|
// debug hooks
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -317,11 +124,9 @@ void sp_scalar_constructor_hook(void * p)
|
|||||||
*pm = adopted_scalar;
|
*pm = adopted_scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
|
void sp_scalar_constructor_hook(void * px, std::size_t, void *)
|
||||||
{
|
{
|
||||||
sp_scalar_constructor_hook(px);
|
sp_scalar_constructor_hook(px);
|
||||||
mutex_type::scoped_lock lock(get_mutex());
|
|
||||||
get_map()[pn] = std::make_pair(px, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sp_scalar_destructor_hook(void * p)
|
void sp_scalar_destructor_hook(void * p)
|
||||||
@@ -336,11 +141,9 @@ void sp_scalar_destructor_hook(void * p)
|
|||||||
*pm = allocated_scalar;
|
*pm = allocated_scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sp_scalar_destructor_hook(void * px, std::size_t /*size*/, void * pn)
|
void sp_scalar_destructor_hook(void * px, std::size_t, void *)
|
||||||
{
|
{
|
||||||
sp_scalar_destructor_hook(px);
|
sp_scalar_destructor_hook(px);
|
||||||
mutex_type::scoped_lock lock(get_mutex());
|
|
||||||
get_map().erase(pn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is not possible to handle the array hooks in a portable manner.
|
// It is not possible to handle the array hooks in a portable manner.
|
||||||
|
100
test/collector_test.cpp
Normal file
100
test/collector_test.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// collector_test.cpp
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Peter Dimov
|
||||||
|
//
|
||||||
|
// Permission to copy, use, modify, sell and distribute this software
|
||||||
|
// is granted provided this copyright notice appears in all copies.
|
||||||
|
// This software is provided "as is" without express or implied
|
||||||
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
// sp_collector.cpp exported functions
|
||||||
|
|
||||||
|
std::size_t find_unreachable_objects(bool report);
|
||||||
|
void free_unreachable_objects();
|
||||||
|
|
||||||
|
struct X
|
||||||
|
{
|
||||||
|
void* fill[32];
|
||||||
|
boost::shared_ptr<X> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
void report()
|
||||||
|
{
|
||||||
|
std::cout << "Calling find_unreachable_objects:\n";
|
||||||
|
|
||||||
|
std::clock_t t = std::clock();
|
||||||
|
|
||||||
|
std::size_t n = find_unreachable_objects(false);
|
||||||
|
|
||||||
|
t = std::clock() - t;
|
||||||
|
|
||||||
|
std::cout << n << " unreachable objects.\n";
|
||||||
|
std::cout << " " << static_cast<double>(t) / CLOCKS_PER_SEC << " seconds.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void free()
|
||||||
|
{
|
||||||
|
std::cout << "Calling free_unreachable_objects:\n";
|
||||||
|
|
||||||
|
std::clock_t t = std::clock();
|
||||||
|
|
||||||
|
free_unreachable_objects();
|
||||||
|
|
||||||
|
t = std::clock() - t;
|
||||||
|
|
||||||
|
std::cout << " " << static_cast<double>(t) / CLOCKS_PER_SEC << " seconds.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::vector< boost::shared_ptr<X> > v1, v2;
|
||||||
|
|
||||||
|
int const n = 256 * 1024;
|
||||||
|
|
||||||
|
std::cout << "Filling v1 and v2\n";
|
||||||
|
|
||||||
|
for(int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
v1.push_back(boost::shared_ptr<X>(new X));
|
||||||
|
v2.push_back(boost::shared_ptr<X>(new X));
|
||||||
|
}
|
||||||
|
|
||||||
|
report();
|
||||||
|
|
||||||
|
std::cout << "Creating the cycles\n";
|
||||||
|
|
||||||
|
for(int i = 0; i < n - 1; ++i)
|
||||||
|
{
|
||||||
|
v2[i]->p = v2[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
v2[n-1]->p = v2[0];
|
||||||
|
|
||||||
|
report();
|
||||||
|
|
||||||
|
std::cout << "Resizing v2 to size of 1\n";
|
||||||
|
|
||||||
|
v2.resize(1);
|
||||||
|
report();
|
||||||
|
|
||||||
|
std::cout << "Clearing v2\n";
|
||||||
|
|
||||||
|
v2.clear();
|
||||||
|
report();
|
||||||
|
|
||||||
|
std::cout << "Clearing v1\n";
|
||||||
|
|
||||||
|
v1.clear();
|
||||||
|
report();
|
||||||
|
|
||||||
|
free();
|
||||||
|
report();
|
||||||
|
}
|
Reference in New Issue
Block a user