Re: Do you use a garbage collector?
"Razii" <DONTwhatevere3e@hotmail.com> wrote in message
news:r84504tsla9563r79shakgbg4r37ju4vjs@4ax.com...
On Sun, 13 Apr 2008 23:41:29 +0200, "Bo Persson" <bop@gmb.dk> wrote:
Isn't that what I said? The new and delete operators are not used very
often in the code. Perhaps only once each in std::allocator, where
they don't allocate int-sized objects, and never 10 million times in a
loop.
std::vector has new and delete. They are still there and must be there
every time memory is allocated dynamically.
That's why the benchmark is silly - you would never do anything like
that in real C++ code.
It's not silly. It's a benchmark that tests dynamic memory allocation
and GC performance.
Let me go ahead and try to quickly augment your test using a VERY simple
caching allocator:
<this should compile...>
____________________________________________________________________
#include <new>
#include <cstddef>
template<typename T>
class cache_allocator {
union node_type {
T m_obj;
node_type* m_next;
};
node_type* m_head;
std::size_t m_depth;
std::size_t const m_max_depth;
public:
cache_allocator(
std::size_t const max_depth = 1024
): m_head(NULL),
m_depth(0),
m_max_depth(max_depth) {
}
~cache_allocator() throw() {
node_type* node = m_head;
while (node) {
node_type* const next = node->m_next;
::operator delete(node);
node = next;
}
}
void sys_destroy(node_type* const node) throw() {
if (m_depth < m_max_depth) {
node->m_next = m_head;
m_head = node;
++m_depth;
} else {
::operator delete(node);
}
}
public:
T* create_ctor() {
node_type* node = m_head;
if (! node) {
node = new (::operator new(sizeof(*node))) node_type;
return &node->m_obj;
}
m_head = node->m_next;
--m_depth;
return new (&node->m_obj) T;
}
void destroy_dtor(T* const obj) {
node_type* node = reinterpret_cast<node_type*>(obj);
try {
obj->~T();
sys_destroy(node);
} catch(...) {
sys_destroy(node);
throw;
}
}
public:
T* create_raw() {
node_type* node = m_head;
if (! node) {
node = new (::operator new(sizeof(*node))) node_type;
return &node->m_obj;
}
m_head = node->m_next;
--m_depth;
return &node->m_obj;
}
void destroy_raw(T* const obj) throw() {
sys_destroy(reinterpret_cast<node_type*>(obj));
}
};
// Your Test...
#include <ctime>
#include <iostream>
#define TREE_CREATE_CACHE_CTOR g_tree_malloc.create_ctor
#define TREE_CREATE_CACHE_RAW g_tree_malloc.create_raw
#define TREE_CREATE_NEW new Tree
#define TREE_DESTROY_CACHE_CTOR(ptr) g_tree_malloc.destroy_dtor(ptr)
#define TREE_DESTROY_CACHE_RAW(ptr) g_tree_malloc.destroy_raw(ptr)
#define TREE_DESTROY_NEW(ptr) delete ptr
#define TREE_CREATE TREE_CREATE_CACHE_RAW
#define TREE_DESTROY TREE_DESTROY_CACHE_RAW
struct Tree
{
Tree *left;
Tree *right;
};
static cache_allocator<Tree> g_tree_malloc;
Tree *CreateTree(int n)
{
if(n <= 0) return NULL;
Tree *t = TREE_CREATE();
t->left = CreateTree(n - 1);
t->right = CreateTree(n - 1);
return t;
}
void DeleteTree(Tree *t)
{
if(t)
{
TREE_DESTROY(t->left);
TREE_DESTROY(t->right);
TREE_DESTROY(t);
}
}
int main(int argc, char *argv[])
{
clock_t start=clock();
for(int i = 0;i < 15;i++) DeleteTree(CreateTree(22));
clock_t endt=clock();
std::cout <<"Time: " <<
double(endt-start)/CLOCKS_PER_SEC * 1000 << " ms\n";
return 0;
}
____________________________________________________________________
What numbers do you get? Does that improve anything?