Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Do you use a garbage collector?

1 view
Skip to first unread message

Lloyd Bonafide

unread,
Apr 10, 2008, 7:57:53 AM4/10/08
to
I followed a link to James Kanze's web site in another thread and was
surprised to read this comment by a link to a GC:

"I can't imagine writing C++ without it"

How many of you c.l.c++'ers use one, and in what percentage of your
projects is one used? I have never used one in personal or professional
C++ programming. Am I a holdover to days gone by?

Daniel Kraft

unread,
Apr 10, 2008, 10:08:40 AM4/10/08
to

I can't tell what professional C++ programming is about or similar, but
I've also never used a GC for any of my projects (and those included
ones with several months of development time and non-trivial structure).

I've never seen the need for it and in fact am rather happy if I can do
the memory management explicitelly rather than by a GC which feels
cleaner to me (BTW, I also only once needed to do reference-counting, so
for those things the "refcounting requires more time than GC"-argument
is out).

Daniel

--
Done: Bar-Sam-Val-Wiz, Dwa-Elf-Hum-Orc, Cha-Law, Fem-Mal
Underway: Ran-Gno-Neu-Fem
To go: Arc-Cav-Hea-Kni-Mon-Pri-Rog-Tou

Juha Nieminen

unread,
Apr 10, 2008, 10:33:21 AM4/10/08
to
Lloyd Bonafide wrote:
> How many of you c.l.c++'ers use one, and in what percentage of your
> projects is one used? I have never used one in personal or professional
> C++ programming. Am I a holdover to days gone by?

I have never used a GC for C++, yet in none of my C++ projects
(professional or hobby) in the last 5+ years have I had a memory leak. I
often use tools such as valgrind and AQTime to check for memory leaks,
and they have yet to report any leak.

There just exists a *style* of programming in C++ which very naturally
leads to encapsulated, clean and safe code. (This style is drastically
different from how, for example, Java programming is usually done.)

One situation where GC *might* help a bit is in efficiency if you are
constantly allocating and deallocating huge amounts of small objects in
tight loops. 'new' and 'delete' in C++ are rather slow operations, and a
well-designed GC might speed things up.
However, part of my C++ programming style just naturally also avoids
doing tons of news and deletes in tight loops (which is, again, very
different from eg. Java programming where you basically have no choice).
Thus this has never been a problem in practice.

Even if I some day stumble across a situation where constant
allocations and deallocations are impacting negatively the speed of a
program, and there just isn't a way around it, I can use a more
efficient allocator than the default one used by the compiler. (I have
measured speedups to up to over 8 times when using an efficient
allocator compared to the default one.)

Pascal J. Bourguignon

unread,
Apr 10, 2008, 11:03:30 AM4/10/08
to
Juha Nieminen <nos...@thanks.invalid> writes:

Now, on another level, I'd say that the problem is that this safe
style you must adopt in C++ to avoid memory leaks is a burden that
forces you to spend your energy in a sterile direction.

More dynamic languages, with a garbage collector, are liberating your
mind, so your free neurons can now think about more interesting
software problems (like for example, AI, or providing a better user
experience, etc).


--
__Pascal Bourguignon__

Noah Roberts

unread,
Apr 10, 2008, 11:19:35 AM4/10/08
to

I use RAII. I've had memory leaks but it's usually due to some third
party application I didn't understand adequately. I was never able to
figure out why AQTime was reporting large chunks of memory loss in my
use of the sqlite3 library for example. We abandoned its use.

Matthias Buelow

unread,
Apr 10, 2008, 11:38:27 AM4/10/08
to
Pascal J. Bourguignon wrote:

> More dynamic languages, with a garbage collector, are liberating your
> mind, so your free neurons can now think about more interesting
> software problems (like for example, AI, or providing a better user
> experience, etc).

Hey now, what's this nonsense against the pure joy if your program looks
totally cryptic, proves that you know the fine details of an 800 pages
thick standard, and runs an infinite loop in under 3 seconds...

lbon...@yahoo.com

unread,
Apr 10, 2008, 11:50:06 AM4/10/08
to
On Apr 10, 10:03 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

> More dynamic languages, with a garbage collector, are liberating your
> mind, so your free neurons can now think about more interesting
> software problems (like for example, AI, or providing a better user
> experience, etc).

You still have to worry about leaking memory (and dereferencing null
pointers) in languages like Java.

http://www.ibm.com/developerworks/library/j-leaks/index.html

Andy Champ

unread,
Apr 10, 2008, 4:06:21 PM4/10/08
to
Pascal J. Bourguignon wrote:
>
> Now, on another level, I'd say that the problem is that this safe
> style you must adopt in C++ to avoid memory leaks is a burden that
> forces you to spend your energy in a sterile direction.
>
> More dynamic languages, with a garbage collector, are liberating your
> mind, so your free neurons can now think about more interesting
> software problems (like for example, AI, or providing a better user
> experience, etc).
>

More dynamic languages, with a garbage collector, are liberating your

mind from worrying about lost resources until one day you realise that
you've run out of GDI objects, or left a file open, or something and it
won't go away until the memory garbage collector decides to clean up the
referencing object. Which it won't do, because you haven't run out of
memory.

GC isn't a magic bullet. You have to know its limitations.

Andy

Juha Nieminen

unread,
Apr 10, 2008, 5:56:15 PM4/10/08
to
Pascal J. Bourguignon wrote:
> Now, on another level, I'd say that the problem is that this safe
> style you must adopt in C++ to avoid memory leaks is a burden that
> forces you to spend your energy in a sterile direction.

I strongly disagree. This style of programming almost automatically
leads to a clean, abstract, encapsulated design, which is only a good thing.

Programmers using languages with GC (such as Java) might not need to
worry about where their dynamically-allocated memory is going, but
neither do I, in most cases. I even dare to claim that at least in some
cases this style of modular programming produces cleaner, simpler, more
understandable and in some cases even more efficient code than a
"mindlessly use 'new' everywhere" style of programming.

I honestly don't feel that I need to put any extra effort to produce
this kind of safe and clean code. Given that I usually like the end
result as a design, even if I have to put that bit of extra effort it's
totally worth it.

> More dynamic languages, with a garbage collector, are liberating your
> mind, so your free neurons can now think about more interesting
> software problems (like for example, AI, or providing a better user
> experience, etc).

I have my doubts that this "liberating" style of programming somehow
automatically leads to clean, modular and abstract designs. All the
contrary, I would even claim that at least in some cases it leads to the
opposite direction ("reckless programming").

Sam

unread,
Apr 10, 2008, 7:19:25 PM4/10/08
to
Lloyd Bonafide writes:

Neither did I.

> Am I a holdover to days gone by?

Probably, if by that you mean "days when young and budding programmers were
actually taught how to program in C++ correctly, instead of some other
language that resembled C++".


Razii

unread,
Apr 10, 2008, 8:14:12 PM4/10/08
to
On Thu, 10 Apr 2008 17:33:21 +0300, Juha Nieminen
<nos...@thanks.invalid> wrote:

> However, part of my C++ programming style just naturally also avoids
>doing tons of news and deletes in tight loops (which is, again, very
>different from eg. Java programming where you basically have no choice)

Howeever, Java allocates new memory blocks on it's internal heap
(which is allocated in huge chunks from the OS). In this way, in most
of the cases it bypasses memory allocation mechanisms of the
underlying OS and is very fast. In C++, each "new" allocation request
will be sent to the operating system, which is slow.


Juha Nieminen

unread,
Apr 10, 2008, 8:35:27 PM4/10/08
to
Razii wrote:
> In C++, each "new" allocation request
> will be sent to the operating system, which is slow.

That's blatantly false.

At least with the memory allocation logic in linux's libc (and I guess
in most other unix systems as well) the only system call that is made is
brk(), which increments the size of the heap. AFAIK this is done in
relatively large chunks to avoid every minuscule 'new' causing a brk()
call. Thus the OS is called relatively rarely. The actual memory
allocation of the blocks allocated with 'new' (or 'malloc') are done by
the routine in libc, not by the OS.

I don't know how Windows compilers do it, but I bet it's something
very similar to this.

I don't see how this is so much different from what Java does.

Chris Thomasson

unread,
Apr 10, 2008, 9:07:57 PM4/10/08
to

"Razii" <DONTwha...@hotmail.com> wrote in message
news:v5btv3lmqeknq5imt...@4ax.com...

You are incorrect. Each call into "new" will "most-likely" be "fast-pathed"
into a "local" cache. On multi-threaded systems, this "cache-hit" can even
be accomplished without using _any_ interlocked RMW or memory barrier
instruction(s). That is, the cache would be per-thread. Some may think that
if a cache is per-thread then a thread will not be able to free something
unless it allocated it. This is false line of thinking. There are different
algorithms that can solve this, one of them can be found here:

http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855

Hoard and StreamFlow also use per-thread heaps.

Razii

unread,
Apr 10, 2008, 9:31:49 PM4/10/08
to
On Thu, 10 Apr 2008 19:14:12 -0500, Razii
<DONTwha...@hotmail.com> wrote:

>> However, part of my C++ programming style just naturally also avoids
>>doing tons of news and deletes in tight loops (which is, again, very
>>different from eg. Java programming where you basically have no choice)

Let's test this about the keyword "new" and tight loops. Because in
most cases Java allocates new memory blocks on it's internal heap and
bypasses memory allocation mechanisms of the underlying OS, the
keyword "new" doesn't mean the same thing that it does in C++, where
each "new" allocation request is sent to the operating system, which
is very slow.

Creating 10000000 new objects with the keyword 'new' in tight loop.

Time: 2125 ms (C++)
Time: 328 ms (java)


--- c++--

#include <ctime>
#include <cstdlib>
#include <iostream>

using namespace std;

class Test {
public:
Test (int c) {count = c;}
virtual ~Test() { }
int count;
};

int main(int argc, char *argv[]) {

clock_t start=clock();
for (int i=0; i<=10000000; i++) {
Test *test = new Test(i);
if (i % 5000000 == 0)
cout << test;
}
clock_t endt=clock();
std::cout <<"Time: " <<
double(endt-start)/CLOCKS_PER_SEC * 1000 << " ms\n";
}

-- java ---

import java.util.*;

class Test {
Test (int c) {count = c;}
int count;

public static void main(String[] arg) {

long start = System.currentTimeMillis();

for (int i=0; i<=10000000; i++) {
Test test = new Test(i);
if (i % 5000000 == 0)
System.out.println (test);
}
long end = System.currentTimeMillis();
System.out.println("Time: " + (end - start) + " ms");

}
}

Razii

unread,
Apr 10, 2008, 9:37:59 PM4/10/08
to
On Fri, 11 Apr 2008 03:35:27 +0300, Juha Nieminen
<nos...@thanks.invalid> wrote:

>Razii wrote:
>> In C++, each "new" allocation request
>> will be sent to the operating system, which is slow.
>
> That's blatantly false.

Well, my friend, I have proven you wrong. Razi has been victorious
once again :)

Arne Vajhøj

unread,
Apr 10, 2008, 9:43:45 PM4/10/08
to
Razii wrote:
> Let's test this about the keyword "new" and tight loops. Because in
> most cases Java allocates new memory blocks on it's internal heap and
> bypasses memory allocation mechanisms of the underlying OS, the
> keyword "new" doesn't mean the same thing that it does in C++, where
> each "new" allocation request is sent to the operating system, which
> is very slow.

I can not imagine any C++ runtime that makes an operating system
call for each new.

The runtime allocates huge chunks from the OS and then manage
it internally.

Arne

Jerry Coffin

unread,
Apr 10, 2008, 9:39:54 PM4/10/08
to
In article <v5btv3lmqeknq5imt...@4ax.com>,
DONTwha...@hotmail.com says...

I know of one library implementation for which this was true (one of the
first 32-bit versions of Visual C++), but it's generally false. Even in
that version of that compiler, the library _contained_ code to allocate
from the OS in large blocks, and then do sub-allocations out of that
block. For reasons known only to Microsoft, that code was disabled by
default.

There is still typically some difference in speed, at least when a
compacting GC is used. Specifically, since this keeps the free memory in
the heap in one large chunk, allocation is done about like on a stack.

By contrast, with a manually managed heap that doesn't do compaction,
you end up with free blocks interspersed with blocks in use. In a really
traditional design, the allocator might round the requested size up to
the next multiple of, say, 16 bytes, and then walk through the list of
free blocks to find one large enough to satisfy the request. When it
found one, it would check the current size of the block, and if it
exceeded the requested size by at least some margin, it would split the
block in two, satisfying the request with one and placing the other back
on the free list.

More recent designs do things like rounding requests to powers of two
(starting from 16 or so), and keeping a separate free list for each
size. Once you've rounded up the size, you search in the correct list,
and either a block is there, or it isn't. If it isn't, you go to the
next larger block size, split that block in half, satisfy the request
with one half, and place the other half on the previously-empty free
list for its new size.

The former version can be quite slow, especially if there are a lot of
free blocks in the system. As you can probably guess, the latter can
improve speed quite a bit.

--
Later,
Jerry.

The universe is a figment of its own imagination.

Razii

unread,
Apr 10, 2008, 9:58:50 PM4/10/08
to
On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <ar...@vajhoej.dk>
wrote:

>I can not imagine any C++ runtime that makes an operating system
>call for each new.
>
>The runtime allocates huge chunks from the OS and then manage
>it internally.

Testing the keyword "new"

Time: 2125 ms (C++)
Time: 328 ms (java)

Explain that. What I am doing different in java than in c++? Code
below..

Mike Schilling

unread,
Apr 10, 2008, 10:04:18 PM4/10/08
to

"Razii" <DONTwha...@hotmail.com> wrote in message
news:99htv3hsa8l5n15df...@4ax.com...

> On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <ar...@vajhoej.dk>
> wrote:
>
>>I can not imagine any C++ runtime that makes an operating system
>>call for each new.
>>
>>The runtime allocates huge chunks from the OS and then manage
>>it internally.
>
> Testing the keyword "new"
>
> Time: 2125 ms (C++)
> Time: 328 ms (java)
>
> Explain that.

The C++ allocator is less efficient. There's a big difference between that
and "makes an OS call for each allocation". In fact, given how highly
optimized Java allocators are these days, the fact that C++ is taking less
than 7 times as long proves that it's *not* making an OS call.


Jerry Coffin

unread,
Apr 10, 2008, 10:14:28 PM4/10/08
to
In article <KKqdncjvUO8DJGPa...@comcast.com>,
cri...@comcast.net says...

[ ... ]

> You are incorrect. Each call into "new" will "most-likely" be "fast-pathed"
> into a "local" cache. On multi-threaded systems, this "cache-hit" can even
> be accomplished without using _any_ interlocked RMW or memory barrier
> instruction(s). That is, the cache would be per-thread. Some may think that
> if a cache is per-thread then a thread will not be able to free something
> unless it allocated it. This is false line of thinking. There are different
> algorithms that can solve this, one of them can be found here:
>
> http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855
>
> Hoard and StreamFlow also use per-thread heaps.

Most of the problem seems to be that people think in terms of a heap
having a single free list, so all other threads have to contend for
access to that free list.

A trivially simple design is for each thread to have its own heap, and
each heap to have one free list for every other thread in the system.
Each other thread can then free blocks to any heap with minimal
possibility of contention (specifically, with the thread whose heap it's
freeing memory TO, and then only if it happens while that thread is
grabbing that free list to coalesce its memory with the other free
blocks.

This contention can normally be reduced to a single atomic exchange to
free memory and another to grab memory for coalescing. Specifically,
consider a structure something like:

struct free_block {
void *next;
size_t size;
size_t origin_threadID;
char payload[0];
};

Technically, that's not legal in C++, but I supect you get the idea.
Let's also assume each thread's heap has a vector of free-lists,
something like:

typedef std:vector<free_block *> free_list;

And we have a vector of free lists, one per thread:

std::vector<free_list> free_lists;

In that case, freeing a block looks something like:

void free_a_block(void *block) {
free_block *f = ((char *)block)-sizeof(free_block);
f->next = f;
size_t heap = f->origin_threadID;
size_t my_threadID = get_current_thread_ID();

atomic_exchange(f->next, free_lists[heap][my_thread_ID]);
}

I.e. we put this block's address into its own 'next' field, and then
exchange that with the pointer to the head of our free list in the
appropriate heap.

If you want to eliminate even the last vestige of a wait, you can go one
step further: have each free list contain _two_ free-list heads instead
of one. At any given time, the owning thread may be using only one of
those. You use a mutex that waits on both, and one of them will always
be free. You update it, and free the mutex. The design isn't lock free,
but it guarantees that you'll never have to wait for the lock to take
place -- both mutexes will be free most of the time, but at least one
will be all the time. The wait for the mutex just determines _which_ one
is free right now.

Of course, in reality that design is generally overkill -- the chances
that all threads will be freeing memory on a single thread's heap at any
given time is minmal to say the least. If we don't mind introducing the
possibility of some waiting, it's pretty trivial to automatically
balance between speed and memory usage -- we start with a single free
list in each heap (and a mutex associated with each free list).

When we want to free a block, we wait on the set of mutexes for a heap,
with a fairly short timeout. If the wait succeeds, we free the memory
and go on our way. If the wait fails, we signal the thread that a wait
failed. After waits fail some number of times, the thread reacts by
increasing the number of available free lists. Both the length of the
wait and the number of failures can be adjusted to balance between
performance and memory usage.

Jerry Coffin

unread,
Apr 10, 2008, 10:14:28 PM4/10/08
to
In article <Xns9A7C46D97C8l...@194.177.96.26>,
nos...@nicetry.org says...

I have used one, but not in quite a while. IIRC, it was in the late '90s
or so when I tried it. I was quite enthused for a little bit, but my
enthusiasm slowly faded, and I think it's been a couple of years or so
since the last time I used it at all. I've never really made any kind of
final decision that I'll never use it again, or anything like that, but
haven't done anything for which I'm convinced it would be at all likely
to provide any real advantage either.

Arne Vajhøj

unread,
Apr 10, 2008, 10:24:34 PM4/10/08
to
Razii wrote:
> On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <ar...@vajhoej.dk>
> wrote:
>> I can not imagine any C++ runtime that makes an operating system
>> call for each new.
>>
>> The runtime allocates huge chunks from the OS and then manage
>> it internally.
>
> Testing the keyword "new"
>
> Time: 2125 ms (C++)
> Time: 328 ms (java)
>
> Explain that. What I am doing different in java than in c++? Code
> below..

If you can prove that the only way to write inefficient code is to make
OS calls, then you have made your point.

But as everyone knows it is not, so your argument is completely bogus.

Arne

Sam

unread,
Apr 10, 2008, 10:29:44 PM4/10/08
to
Razii writes:

> On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <ar...@vajhoej.dk>
> wrote:
>
>>I can not imagine any C++ runtime that makes an operating system
>>call for each new.
>>
>>The runtime allocates huge chunks from the OS and then manage
>>it internally.
>
> Testing the keyword "new"
>
> Time: 2125 ms (C++)
> Time: 328 ms (java)
>
> Explain that. What I am doing different in java than in c++? Code
> below..

What you're doing different in Java is that you're using the part of the
language that it's optimized for. Java is, generally, optimized for fast
instantiation of discrete objects on the heap, because creating a huge
number of objects is unavoidable in Java, and they all have to be allocated
on the heap, due to the nature of the language itself.

On the other case, in most use cases C++ does not require instantiation of
as many discrete objects on the heap that Java does, for implementing an
equivalent task. In C++, most -- if not all -- of these objects can be
easily allocated on the stack.

So, if you were to do a fair comparison, you should benchmark instantiation
of Java objects, on the heap, against instantiation of C++ objects on the
stack.

And then benchmark the comparable memory usage, to boot :-)

In your C++ example, there was no reason whatsoever to instantiate your C++
test object on the heap. What does that accomplish, besides a memory leak?
That's just the Java way of doing things, but, in C++ you have the option of
instantiating objects on the stack, so try benchmarking this instead:

int main(int argc, char *argv[]) {
clock_t start=clock();
for (int i=0; i<=10000000; i++)
{

Test testObj(i);

if (i % 5000000 == 0)

cout << &testObj << endl;
}

clock_t endt=clock();
std::cout <<"Time: " <<
double(endt-start)/CLOCKS_PER_SEC * 1000 << " ms\n";
}

See how well /that/ benchmarks against Java :-)


Razii

unread,
Apr 10, 2008, 10:39:13 PM4/10/08
to
On Thu, 10 Apr 2008 22:24:34 -0400, Arne Vajhøj <ar...@vajhoej.dk>
wrote:

>But as everyone knows it is not, so your argument is completely bogus.

What argument is bogus? My point was that the keyword 'new' is much
faster in java because JVM allocates new memory blocks on it's


internal heap and bypasses memory allocation mechanisms of the

underlying OS. If that's not the right explanation, then you need to
post a different explanation why I get these numbers with using the
keyword 'new' in c++.

Time: 2125 ms (C++)
Time: 328 ms (java)

Time: 172 ms (java - server)
Time: 438 ms (JET native java compiler).

Razii

unread,
Apr 10, 2008, 10:40:47 PM4/10/08
to
On Fri, 11 Apr 2008 02:04:18 GMT, "Mike Schilling"
<mscotts...@hotmail.com> wrote:

> In fact, given how highly
>optimized Java allocators are these days, the fact that C++ is taking less
>than 7 times as long proves that it's *not* making an OS call.

with java -server it's 12 times slower...

Time: 2125 ms (g++)

Ian Collins

unread,
Apr 10, 2008, 10:41:58 PM4/10/08
to
Razii wrote:
> On Thu, 10 Apr 2008 19:14:12 -0500, Razii
> <DONTwha...@hotmail.com> wrote:
>
>>> However, part of my C++ programming style just naturally also avoids
>>> doing tons of news and deletes in tight loops (which is, again, very
>>> different from eg. Java programming where you basically have no choice)
>
> Let's test this about the keyword "new" and tight loops. Because in
> most cases Java allocates new memory blocks on it's internal heap and
> bypasses memory allocation mechanisms of the underlying OS, the
> keyword "new" doesn't mean the same thing that it does in C++, where
> each "new" allocation request is sent to the operating system, which
> is very slow.
>
> Creating 10000000 new objects with the keyword 'new' in tight loop.
>
If a C++ programmer had to do this in the most efficient way possible,
he/she would use a custom allocator.

> int main(int argc, char *argv[]) {
>
> clock_t start=clock();
> for (int i=0; i<=10000000; i++) {
> Test *test = new Test(i);
> if (i % 5000000 == 0)
> cout << test;
> }

Leaks 10000000 objects.

>
> for (int i=0; i<=10000000; i++) {
> Test test = new Test(i);
> if (i % 5000000 == 0)
> System.out.println (test);
> }

Does the Java allocator/GC combination recycle the objects in the loop?

--
Ian Collins.

Peter Duniho

unread,
Apr 10, 2008, 10:43:16 PM4/10/08
to
On Thu, 10 Apr 2008 19:24:34 -0700, Arne Vajhøj <ar...@vajhoej.dk> wrote:

> [...]


> But as everyone knows it is not, so your argument is completely bogus.

So what else is new?

What I can't figure out is, why do people continue to feed this troll,
especially when he keeps cross-posting these dopey threads to both the
C++ and Java newsgroups?

I've got as many thread filters to junk stuff he started as I do for
spam. He has really suckered a bunch of you in (including people I'm
surprised could be suckered).

Razii

unread,
Apr 10, 2008, 10:50:29 PM4/10/08
to
On Fri, 11 Apr 2008 14:41:58 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>Does the Java allocator/GC combination recycle the objects in the loop?

I doubt it (not sure though). It ends too fast for that. If it was
longer running program, then probably GC will kick in.


Razii

unread,
Apr 10, 2008, 10:58:24 PM4/10/08
to
On Thu, 10 Apr 2008 21:29:44 -0500, Sam <s...@email-scan.com> wrote:

>See how well /that/ benchmarks against Java :-)


That is not the topic. The topic is how the keyword "new" behaves.

0x12ff5c
0x12ff5c
0x12ff5c
Time: 62 ms

All the references are the same -- not the same output as in the last
version (or java version).

Razii

unread,
Apr 10, 2008, 11:23:49 PM4/10/08
to
On Thu, 10 Apr 2008 21:29:44 -0500, Sam <s...@email-scan.com> wrote:

>Java is, generally, optimized for fast
>instantiation of discrete objects on the heap, because creating a huge
>number of objects is unavoidable in Java, and they all have to be allocated
>on the heap, due to the nature of the language itself.

As I said, Java allocates new memory blocks on it's internal heap
which is allocated in huge chunks from the OS. That's why the "new" in
Java is 12 times faster than C++ version. If there is any other
explanation, post it (I haven't seen it).

Roedy Green

unread,
Apr 10, 2008, 11:24:16 PM4/10/08
to
On Thu, 10 Apr 2008 20:31:49 -0500, Razii
<DONTwha...@hotmail.com> wrote, quoted or indirectly quoted
someone who said :

>Creating 10000000 new objects with the keyword 'new' in tight loop.

All Java has to do is add N (the size of the object) to a counter and
zero out the object. In C++ it also has to look for a hole the right
size and record it is some sort of collection. C++ typically does not
move objects once allocated. Java does.

In my C++ days, we used NuMega to find leaks, objects that were
allocated butw never deleted even after there were no references to
them. We never got anywhere near nailing them all. With Java this is
automatic. You can't make that sort of screw up, though you can
packrat. See http://mindprod.com/jgloss/packratting.html
--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Mike Schilling

unread,
Apr 10, 2008, 11:34:56 PM4/10/08
to

"Razii" <DONTwha...@hotmail.com> wrote in message
news:sqjtv3lqhj3pjq6t5...@4ax.com...

Which doesn't change the conclusion.


Mike Schilling

unread,
Apr 10, 2008, 11:35:53 PM4/10/08
to

"Razii" <DONTwha...@hotmail.com> wrote in message
news:acjtv3d5usvc1h668...@4ax.com...

> On Thu, 10 Apr 2008 22:24:34 -0400, Arne Vajhøj <ar...@vajhoej.dk>
> wrote:
>
>>But as everyone knows it is not, so your argument is completely
>>bogus.
>
> What argument is bogus? My point was that the keyword 'new' is much
> faster in java because JVM allocates new memory blocks on it's
> internal heap and bypasses memory allocation mechanisms of the
> underlying OS.

And you're wrong, as has been demonstrated repeatedly. There's no
point trying to explain this any further.


Ian Collins

unread,
Apr 10, 2008, 11:39:36 PM4/10/08
to
Razii wrote:
> On Thu, 10 Apr 2008 21:29:44 -0500, Sam <s...@email-scan.com> wrote:
>
>> See how well /that/ benchmarks against Java :-)
>
>
> That is not the topic. The topic is how the keyword "new" behaves.
>
The change was fair, it compares idiomatic language use.

Anyhow, a if you are looking at the keyword new, as simple change to the
Test class,

class Test
{
static const unsigned nItems(10000001);

public:
Test (int c = 0) : count(c) {}
int count;
void*

operator new( size_t n ) throw( std::bad_alloc )
{
static Test* items = static_cast<Test*>(malloc(sizeof *items * nItems));
static unsigned next(0);

if( next >= nItems ) throw std::bad_alloc();

return &items[next++];
}

void operator delete( void* v ) throw() {}
};

runs in 90mS on my box (compared to ~940mS with default new).

As other's have said, something that's idiomatic Java isn't necessarily
idiomatic C++. Sam pointed you to the idiomatic C++ code, my example
shows what a C++ programmer can do when forced to use an unnatural idiom.

--
Ian Collins.

Razii

unread,
Apr 10, 2008, 11:56:28 PM4/10/08
to
On Fri, 11 Apr 2008 15:39:36 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>runs in 90mS on my box (compared to ~940mS with default new).

Doesn't compile..


new.cpp:4:21: error: bad_alloc: No such file or directory
new.cpp:10: error: expected identifier before numeric constant
new.cpp:10: error: expected ',' or '...' before numeric constant
new.cpp: In static member function 'static void* Test::operator
new(size_t)':
new.cpp:19: error: invalid operands of types 'unsigned int' and 'const
unsigned
int ()(int)' to binary 'operator*'
new.cpp:22: error: ISO C++ forbids comparison between pointer and
integer

Razii

unread,
Apr 10, 2008, 11:57:44 PM4/10/08
to
On Fri, 11 Apr 2008 03:24:16 GMT, Roedy Green
<see_w...@mindprod.com.invalid> wrote:

>All Java has to do is add N (the size of the object) to a counter and
>zero out the object.

I am not sure what you mean by that ... can you post the code?

Razii

unread,
Apr 11, 2008, 12:05:36 AM4/11/08
to
On Thu, 10 Apr 2008 19:43:16 -0700, "Peter Duniho"
<NpOeS...@nnowslpianmk.com> wrote:

> when he keeps cross-posting these dopey threads to both the
>C++ and Java newsgroups?

Because the topic relates to both newsgroup. The topic was not started
by me. Juha Nieminen and many others were already discussing Java and
C++. I responded to their post and since it's on topic on both
newsgroup, it's appropriate to cross post it to both newsgroup. There
is a reason why cross posting is allowed on USENET, and you should use
it whenever appropriate.


Razii

unread,
Apr 11, 2008, 12:16:15 AM4/11/08
to
On Thu, 10 Apr 2008 08:50:06 -0700 (PDT), lbon...@yahoo.com wrote:

>You still have to worry about leaking memory (and dereferencing null
>pointers) in languages like Java.
>
>http://www.ibm.com/developerworks/library/j-leaks/index.html


True memory leaks memory are impossible, other than by holding
references to objects that are not needed. Also, according the site
above, in C++ memory is never returned to the operating system (at
least the older OS), even after the application is closed. This can
never happen in Java.

Ian Collins

unread,
Apr 11, 2008, 12:20:26 AM4/11/08
to
Razii wrote:
> On Fri, 11 Apr 2008 15:39:36 +1200, Ian Collins <ian-...@hotmail.com>
> wrote:
>
>> runs in 90mS on my box (compared to ~940mS with default new).
>
> Doesn't compile..
>
#include <new>

--
Ian Collins.

Chris Thomasson

unread,
Apr 11, 2008, 1:05:11 AM4/11/08
to
"Jerry Coffin" <jco...@taeus.com> wrote in message
news:MPG.226875e66...@news.sunsite.dk...

> In article <KKqdncjvUO8DJGPa...@comcast.com>,
> cri...@comcast.net says...
>
> [ ... ]
>
>> You are incorrect. Each call into "new" will "most-likely" be
>> "fast-pathed"
>> into a "local" cache. On multi-threaded systems, this "cache-hit" can
>> even
>> be accomplished without using _any_ interlocked RMW or memory barrier
>> instruction(s). That is, the cache would be per-thread. Some may think
>> that
>> if a cache is per-thread then a thread will not be able to free something
>> unless it allocated it. This is false line of thinking. There are
>> different
>> algorithms that can solve this, one of them can be found here:
>>
>> http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855
>>
>> Hoard and StreamFlow also use per-thread heaps.
>
> Most of the problem seems to be that people think in terms of a heap
> having a single free list, so all other threads have to contend for
> access to that free list.

I agree; most of those people have not implemented a high-performance
scaleable memory allocator.


> A trivially simple design is for each thread to have its own heap, and
> each heap to have one free list for every other thread in the system.

How does this efficently handle dynamic numbers of threads that can, and
will be created and joined with, or detached, during the lifetime of a given
process? It seems like you are describing a fully connected network. One
freelist per-thread, that holds N buckets, where N == current number of
threads at any one time. This implies that N is an unknown variable,
therefore, if user creates a number of threads, so on a high-end system with
many cores, they must all be interconnected. Each threads heap needs an
entry for a thread in the system, if a new thread gets added, it must auto
register, or register on "first" usage; think 'pthread_once()'.

There are some discussions here:

http://groups.google.com/group/comp.programming.threads/msg/13879a3dec53169a

which is within the following thread:

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e082e1eb26397d5e

Your right, atomic XCHG gets executed when a thread hits an "exhausted
per-thread heap" state. This XCHG will reuse memory that any _other_ threads
have previously passed back to the calling thread. A "remote free" can use a
CAS, or it can simply use message-passing to notify any of the origin
threads subsequent logically failed allocation requests. Logically fails
means that a thread did not hit the fast-path. It needs to use an
interlocked RMW instruction, or use distributed messaging.
Single-Producer/Consumer queues work well, _only_ when properly managed of
course.


> Each other thread can then free blocks to any heap with minimal
> possibility of contention (specifically, with the thread whose heap it's
> freeing memory TO, and then only if it happens while that thread is
> grabbing that free list to coalesce its memory with the other free
> blocks.

If you are using a dynamic network, you can easily use
single-producer/consumer queuing. Anybody who as been reading 'c.p.t' knows
where to look for source-code. You can multiplex a given threads registered
queues, and apply priorities.


> This contention can normally be reduced to a single atomic exchange to
> free memory and another to grab memory for coalescing. Specifically,
> consider a structure something like:
>
> struct free_block {
> void *next;
> size_t size;
> size_t origin_threadID;
> char payload[0];
> };

Actually, the free-block only needs to be == to sizeof(void*):

http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855

http://groups.google.com/group/comp.programming.threads/msg/bc019dc04362be41

http://groups.google.com/group/comp.programming.threads/msg/1d3aeaa6ebf5181f


> Technically, that's not legal in C++, but I supect you get the idea.
> Let's also assume each thread's heap has a vector of free-lists,
> something like:
>
> typedef std:vector<free_block *> free_list;
>
> And we have a vector of free lists, one per thread:
>
> std::vector<free_list> free_lists;
>
> In that case, freeing a block looks something like:
>
> void free_a_block(void *block) {
> free_block *f = ((char *)block)-sizeof(free_block);
> f->next = f;
> size_t heap = f->origin_threadID;
> size_t my_threadID = get_current_thread_ID();
>
> atomic_exchange(f->next, free_lists[heap][my_thread_ID]);
> }
>
> I.e. we put this block's address into its own 'next' field, and then
> exchange that with the pointer to the head of our free list in the
> appropriate heap.

Simple scheme:

http://groups.google.com/group/comp.arch/browse_frm/thread/6dc825ec9999d3a8
(read all...)


[...]

If you really care about utmost portability, use a single mutex per-thread,
and an algorithm similar to the one contained within the third link I cited
in this post. Otherwise, you can tack advantage of per-architecture
builds... IMHO, thinking in per-thread distributed efficient communications
is definitely worthwhile.

Razii

unread,
Apr 11, 2008, 1:11:56 AM4/11/08
to
On Fri, 11 Apr 2008 16:20:26 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>#include <new>

that was not it...

static const unsigned nItems (10000001);

should be..

static const unsigned nItems = 10000001;

Time: 78 ms

pretty fast...

however, if I change the loop to 10000003, the class has to change as
well.

Lew

unread,
Apr 11, 2008, 1:24:24 AM4/11/08
to

Amen to that, brother.

--
Lew

Ian Collins

unread,
Apr 11, 2008, 1:26:01 AM4/11/08
to
Razii wrote:

>
> Time: 78 ms
>
> pretty fast...
>
> however, if I change the loop to 10000003, the class has to change as
> well.
>

That's not the point. The example was merely an illustration of how
object allocation can be optimised if required.

Custom allocators are a common optimisation in C++ where many small
objects are dynamically allocated.

--
Ian Collins.

Lew

unread,
Apr 11, 2008, 1:26:33 AM4/11/08
to

Don't feed the trolls.

--
Lew

Chris Thomasson

unread,
Apr 11, 2008, 1:28:17 AM4/11/08
to
"Roedy Green" <see_w...@mindprod.com.invalid> wrote in message
news:s7mtv3p1c55bd4v6v...@4ax.com...

> On Thu, 10 Apr 2008 20:31:49 -0500, Razii
> <DONTwha...@hotmail.com> wrote, quoted or indirectly quoted
> someone who said :
>
>>Creating 10000000 new objects with the keyword 'new' in tight loop.
>
> All Java has to do is add N (the size of the object) to a counter and
> zero out the object.

[...]

No. What type of counter are you talking about? A distributed counter? A
single global counter? How do the threads interact with the counter? If you
use a single variable, and interlocked RMW instructions, well, then your
going to hit contention on the singular instance of a global counter. Why
not distribute the count, and create two versions of a interrogate type
function that can get approximate counts, or one that "tries harder"...
Think how you would implement a counter on a super-computer?

On something that is analogous to a "super-computer":

http://www.sicortex.com

Lew

unread,
Apr 11, 2008, 1:33:06 AM4/11/08
to
Chris Thomasson wrote:
> "Roedy Green" <see_w...@mindprod.com.invalid> wrote in message
> news:s7mtv3p1c55bd4v6v...@4ax.com...
>> On Thu, 10 Apr 2008 20:31:49 -0500, Razii
>> <DONTwha...@hotmail.com> wrote, quoted or indirectly quoted
>> someone who said :
>>
>>> Creating 10000000 new objects with the keyword 'new' in tight loop.
>>
>> All Java has to do is add N (the size of the object) to a counter and
>> zero out the object.
>
> [...]
>
> No. What type of counter are you talking about? A distributed counter? A
> single global counter? How do the threads interact with the counter? If
> you use a single variable, and interlocked RMW instructions, well, then
> your going to hit contention on the singular instance of a global
> counter. Why not distribute the count, and create two versions of a
> interrogate type function that can get approximate counts, or one that
> "tries harder"...

To what are you saying no?

Roedy's speaking of a memory pointer, managed by the JVM itself. The
programmer never allocates a "counter" explicitly, they just call on the 'new'
operator. Such an action is always thread local at least until the memory
allocation part of 'new' completes, although the constructor could (likely
foolishly) start a thread after that. Your points have nothing whatsoever to
do with memory allocation in Java, Chris.

Java memory allocation takes a handful or two of machine instructions that
simply increment a pointer in memory. Boom, done. No hunting for suitable
holes.

There's no "count" to "distribute" in that action, whatever the heck you meant
by that.

--
Lew

Chris Thomasson

unread,
Apr 11, 2008, 1:34:32 AM4/11/08
to
"Ian Collins" <ian-...@hotmail.com> wrote in message
news:668b39F2...@mid.individual.net...

Indeed. Everybody should know how to program these basic techniques.

Chris Thomasson

unread,
Apr 11, 2008, 1:36:54 AM4/11/08
to
"Lew" <l...@lewscanon.com> wrote in message
news:mq6dnbwwrqSPZWPa...@comcast.com...

> Chris Thomasson wrote:
>> "Roedy Green" <see_w...@mindprod.com.invalid> wrote in message
>> news:s7mtv3p1c55bd4v6v...@4ax.com...
>>> On Thu, 10 Apr 2008 20:31:49 -0500, Razii
>>> <DONTwha...@hotmail.com> wrote, quoted or indirectly quoted
>>> someone who said :
>>>
>>>> Creating 10000000 new objects with the keyword 'new' in tight loop.
>>>
>>> All Java has to do is add N (the size of the object) to a counter and
>>> zero out the object.
>>
>> [...]
>>
>> No. What type of counter are you talking about? A distributed counter? A
>> single global counter? How do the threads interact with the counter? If
>> you use a single variable, and interlocked RMW instructions, well, then
>> your going to hit contention on the singular instance of a global
>> counter. Why not distribute the count, and create two versions of a
>> interrogate type function that can get approximate counts, or one that
>> "tries harder"...
>
> To what are you saying no?
>
> Roedy's speaking of a memory pointer, managed by the JVM itself. The
> programmer never allocates a "counter" explicitly, they just call on the
> 'new' operator.

[...]

Before I answer you, please try and answer a simple question:

If thread A allocates 256 bytes, and thread B races in and concurrently
attempts to allocate 128 bytes... Which thread is going to win?

Razii

unread,
Apr 11, 2008, 1:40:04 AM4/11/08
to
On Fri, 11 Apr 2008 03:35:53 GMT, "Mike Schilling"
<mscotts...@hotmail.com> wrote:

>And you're wrong, as has been demonstrated repeatedly. There's no
>point trying to explain this any further.

There was nothing wrong with my basic premise that creating objects
with on heap is much faster in java than in c++. Google search
confirms..


---- quote---------
Creating heap objects in C++ is typically much slower because it's
based on the C concept of a heap as a big pool of memory that (and
this is essential) must be recycled. When you call delete in C++ the
released memory leaves a hole in the heap, so when you call new, the
storage allocation mechanism must go seeking to try to fit the storage
for your object into any existing holes in the heap or else you'll
rapidly run out of heap storage. Searching for available pieces of
memory is the reason that allocating heap storage has such a
performance impact in C++, so it's far faster to create stack-based
objects.

Again, because so much of C++ is based on doing everything at
compile-time, this makes sense. But in Java there are certain places
where things happen more dynamically and it changes the model. When it
comes to creating objects, it turns out that the garbage collector can
have a significant impact on increasing the speed of object creation.
This might sound a bit odd at first - that storage release affects
storage allocation - but it's the way some JVMs work and it means that
allocating storage for heap objects in Java can be nearly as fast as
creating storage on the stack in C++.

[...] In some JVMs, the Java heap is quite different; it's more like a
conveyor belt that moves forward every time you allocate a new object.
This means that object storage allocation is remarkably rapid. The
"heap pointer" is simply moved forward into virgin territory, so it's
effectively the same as C++'s stack allocation. (Of course, there's a
little extra overhead for bookkeeping but it's nothing like searching
for storage.)

Now you might observe that the heap isn't in fact a conveyor belt, and
if you treat it that way you'll eventually start paging memory a lot
(which is a big performance hit) and later run out. The trick is that
the garbage collector steps in and while it collects the garbage it
compacts all the objects in the heap so that you've effectively moved
the "heap pointer" closer to the beginning of the conveyor belt and
further away from a page fault. The garbage collector rearranges
things and makes it possible for the high-speed, infinite-free-heap
model to be used while allocating storage.

Chris Thomasson

unread,
Apr 11, 2008, 1:42:00 AM4/11/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:h-WdnXpVLJQ6ZWPa...@comcast.com...

Oh yeah... Thread C tries to allocate just before thread B...


Which thread is going to win?


A, B or C. Do the set of answers seem okay with you?


Thing of how a single global pointer to a shared virtual memory range can be
distributed and efficiently managed...

Mike Schilling

unread,
Apr 11, 2008, 1:47:39 AM4/11/08
to

"Razii" <DONTwha...@hotmail.com> wrote in message
news:apstv398bi7jf5cnb...@4ax.com...

> On Fri, 11 Apr 2008 03:35:53 GMT, "Mike Schilling"
> <mscotts...@hotmail.com> wrote:
>
>>And you're wrong, as has been demonstrated repeatedly. There's no
>>point trying to explain this any further.
>
> There was nothing wrong with my basic premise that creating objects
> with on heap is much faster in java than in c++.

Your premise was that each C++ "new" does a system call.. That's
nonsense, as what you quote below demonstrates.

Razii

unread,
Apr 11, 2008, 1:49:37 AM4/11/08
to
On Fri, 11 Apr 2008 01:26:33 -0400, Lew <l...@lewscanon.com> wrote:

>Don't feed the trolls.

The guy turned into a whiner (like stan) whose only contribution to a
legitimate thread is posting on-liners that are far more annoying than
legitimate discussion, like my posts. If he continues with that I will
PLONK him too. That will be second one after stan.

Razii

unread,
Apr 11, 2008, 3:07:19 AM4/11/08
to
On Fri, 11 Apr 2008 14:41:58 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>Does the Java allocator/GC combination recycle the objects in the loop?

Oh, I figured it out... the flag is -verbose:gc

so trying this time now with.

java -verbose:gc -server Test>log.txt

and log.txt includes......

Test@19f953d
[GC 896K->108K(5056K), 0.0018061 secs]
[GC 1004K->108K(5056K), 0.0004453 secs]
[GC 1004K->108K(5056K), 0.0001847 secs]
[GC 1004K->108K(5056K), 0.0000500 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000506 secs]
[GC 1004K->108K(5056K), 0.0000483 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000497 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000955 secs]
[GC 1004K->108K(5056K), 0.0000494 secs]
[GC 1004K->108K(5056K), 0.0000464 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000486 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000531 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000534 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000534 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000592 secs]
[GC 1004K->108K(5056K), 0.0000464 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000486 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000601 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
Test@e86da0
[GC 1004K->108K(5056K), 0.0000528 secs]
[GC 1004K->108K(5056K), 0.0000464 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000545 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000464 secs]
[GC 1004K->108K(5056K), 0.0000486 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000489 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000464 secs]
[GC 1004K->108K(5056K), 0.0000612 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000902 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000601 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000503 secs]
[GC 1004K->108K(5056K), 0.0000483 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000623 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000673 secs]
[GC 1004K->108K(5056K), 0.0000461 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000458 secs]
[GC 1004K->108K(5056K), 0.0000478 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000623 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000472 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
[GC 1004K->108K(5056K), 0.0000469 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000475 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000453 secs]
[GC 1004K->108K(5056K), 0.0000481 secs]
[GC 1004K->108K(5056K), 0.0000514 secs]
[GC 1004K->108K(5056K), 0.0000455 secs]
Test@1975b59
Time: 172 ms

Razii

unread,
Apr 11, 2008, 3:13:49 AM4/11/08
to
On Fri, 11 Apr 2008 17:26:01 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>That's not the point. The example was merely an illustration of how


>object allocation can be optimised if required.

Where are these objects deleted .. does the time includes that? As I
showed in the loop, in the case of java GC collects most of these
objects in the loop.


Razii

unread,
Apr 11, 2008, 3:20:47 AM4/11/08
to
On Thu, 10 Apr 2008 20:37:59 -0500, Razii
<DONTwha...@hotmail.com> wrote:

>int main(int argc, char *argv[]) {
>
> clock_t start=clock();
> for (int i=0; i<=10000000; i++) {
> Test *test = new Test(i);
> if (i % 5000000 == 0)
> cout << test;
> }

If I add delete test; to this loop it gets faster. huh? what the
exaplanation for this?

2156 ms

and after I add delete test; to the loop

1781 ms

why is that?


asterisc

unread,
Apr 11, 2008, 3:31:30 AM4/11/08
to
On Apr 11, 10:20 am, Razii <DONTwhatever...@hotmail.com> wrote:
> On Thu, 10 Apr 2008 20:37:59 -0500, Razii
>
> <DONTwhatever...@hotmail.com> wrote:
> >int main(int argc, char *argv[]) {
>
> > clock_t start=clock();
> > for (int i=0; i<=10000000; i++) {
> > Test *test = new Test(i);
> > if (i % 5000000 == 0)
> > cout << test;
> > }
>
> If I add delete test; to this loop it gets faster. huh? what the
> exaplanation for this?
>
> 2156 ms
>
> and after I add delete test; to the loop
>
> 1781 ms
>
> why is that?

Probably because of some compiler's optimizations.

When do you free memory in Java? Before or after you stop the clock?

Ian Collins

unread,
Apr 11, 2008, 3:35:52 AM4/11/08
to
Razii wrote:
> On Thu, 10 Apr 2008 20:37:59 -0500, Razii
> <DONTwha...@hotmail.com> wrote:
>
>> int main(int argc, char *argv[]) {
>>
>> clock_t start=clock();
>> for (int i=0; i<=10000000; i++) {
>> Test *test = new Test(i);
>> if (i % 5000000 == 0)
>> cout << test;
>> }
>
> If I add delete test; to this loop it gets faster. huh? what the
> exaplanation for this?
>
You have just disproved your original hypothesis. Memory is returned to
the allocator, so it doesn't have to keep fetching more from the system.

--
Ian Collins.

Ian Collins

unread,
Apr 11, 2008, 3:38:55 AM4/11/08
to
As I pointed out earlier, you are leaking memory. Didn't you realise
that? Do you read peoples responses?

--
Ian Collins.

Razii

unread,
Apr 11, 2008, 3:43:50 AM4/11/08
to
On Fri, 11 Apr 2008 00:31:30 -0700 (PDT), asterisc <Rare...@ni.com>
wrote:

>When do you free memory in Java? Before or after you stop the clock?


You don't. When an object is no longer referenced by the program, the
GC will recycled it. The space is made available for subsequent new
objects.

Razii

unread,
Apr 11, 2008, 3:51:40 AM4/11/08
to
On Fri, 11 Apr 2008 19:38:55 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>As I pointed out earlier, you are leaking memory. Didn't you realise
>that?

In the original C++ version I was leaking memory and I knew that. I
deliberately made it that way since I wasn't sure whether GC will run
at all in java version in such a short running application. However,
as it turns out, adding delete makes the C++ version faster. If I knew
that, I would have added it.


Razii

unread,
Apr 11, 2008, 3:46:47 AM4/11/08
to
On Fri, 11 Apr 2008 19:35:52 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>You have just disproved your original hypothesis.

My number one hypothesis was that "new" is faster in java than in c++.
It doesn't behave the same way as in c++. I was speculating that the
reason for that is call to operating system in c++.


asterisc

unread,
Apr 11, 2008, 3:58:30 AM4/11/08
to
On Apr 11, 10:43 am, Razii <DONTwhatever...@hotmail.com> wrote:
> On Fri, 11 Apr 2008 00:31:30 -0700 (PDT), asterisc <Rares....@ni.com>

> wrote:
>
> >When do you free memory in Java? Before or after you stop the clock?
>
> You don't. When an object is no longer referenced by the program, the
> GC will recycled it. The space is made available for subsequent new
> objects.

Let me rephrase that:
When exactly is the memory deallocated? Before or after you stop the
clock?
Do you know exactly when the GC will free the memory ?

I think the memory for every new is not referenced outside the loop.
Does GC run in every loop step?
Can you print out a message like: "here is allocated at address: xxx"
and "here is deallocated from address: xxx"

What you said is pure theory. I'm worried about how is that in
practice...

Ian Collins

unread,
Apr 11, 2008, 4:06:08 AM4/11/08
to
You claimed "In C++, each "new" allocation request will be sent to the
operating system, which is slow."

You have just disproved this by comparing the performance with and
without returning memory to the allocator. If each new requested memory
from the system, the performance would not have changed so
significantly.

--
Ian Collins.

Razii

unread,
Apr 11, 2008, 4:15:53 AM4/11/08
to
On Fri, 11 Apr 2008 00:58:30 -0700 (PDT), asterisc <Rare...@ni.com>
wrote:

>When exactly is the memory deallocated? Before or after you stop the
>clock?

I already posted the output in the other post. The clock stops when
this is printed.

long end = System.currentTimeMillis();
System.out.println("Time: " + (end - start) + " ms");

The GC (in a different thread) runs several times while the main
thread is in the loop.

Once the main() thread ends, all the memory is returned to the
operating system by the JVM anyway.


Test@19f953d <----printed when i == 0

Test@e86da0 <----printed when i == 5000000

Test@1975b59 <----printed when i == 10000000
Time: 172 ms

asterisc

unread,
Apr 11, 2008, 4:18:30 AM4/11/08
to
On Apr 11, 11:15 am, Razii <DONTwhatever...@hotmail.com> wrote:
> On Fri, 11 Apr 2008 00:58:30 -0700 (PDT), asterisc <Rares....@ni.com>

Can you print out a message like: "here is allocated at address: xxx"

asterisc

unread,
Apr 11, 2008, 4:19:41 AM4/11/08
to
On Apr 11, 11:15 am, Razii <DONTwhatever...@hotmail.com> wrote:
> On Fri, 11 Apr 2008 00:58:30 -0700 (PDT), asterisc <Rares....@ni.com>

Can you print out a message like: "here is allocated at address: xxx"

asterisc

unread,
Apr 11, 2008, 4:20:42 AM4/11/08
to
On Apr 11, 11:15 am, Razii <DONTwhatever...@hotmail.com> wrote:
> On Fri, 11 Apr 2008 00:58:30 -0700 (PDT), asterisc <Rares....@ni.com>

Can you print out a message like: "here is allocated at address: xxx"

Razii

unread,
Apr 11, 2008, 4:22:34 AM4/11/08
to
On Fri, 11 Apr 2008 20:06:08 +1200, Ian Collins <ian-...@hotmail.com>
wrote:

>You claimed "In C++, each "new" allocation request will be sent to the


>operating system, which is slow."

Yes, I did say that based on what I read on a web site. That was his
explanation regarding why allocating memory with new is slower in c++.

Matthias Buelow

unread,
Apr 11, 2008, 5:21:44 AM4/11/08
to
Juha Nieminen wrote:

> I have my doubts that this "liberating" style of programming somehow
> automatically leads to clean, modular and abstract designs. All the
> contrary, I would even claim that at least in some cases it leads to the
> opposite direction ("reckless programming").

And your point is? The simple fact is, that bad programmers write bad
code, and good programmers write good code, no matter what the language
is or whether memory is managed automatically or manually.

Matthias Buelow

unread,
Apr 11, 2008, 5:24:09 AM4/11/08
to
Razii wrote:

> Yes, I did say that based on what I read on a web site. That was his
> explanation regarding why allocating memory with new is slower in c++.

Maybe you shouldn't believe everything you read on a web site.

Razii

unread,
Apr 11, 2008, 5:43:50 AM4/11/08
to
On Fri, 11 Apr 2008 01:18:30 -0700 (PDT), asterisc <Rare...@ni.com>
wrote:

>Can you print out a message like: "here is allocated at address: xxx"


>and "here is deallocated from address: xxx"

What would be the point? Everything is clear here.

[GC 1004K->108K(5056K), 0.0000464 secs]

GC == Garbage Collection.
1004K == Heap in use before collection.
108K == heap in use after collection.
5056K == Total heap size

0.0000464 secs == time it took.

There were a total of 174 of these outputs. That means,

0.0000464 * 174 = 0.0080736 sec == 8 ms

GC took 8 ms total...


asterisc

unread,
Apr 11, 2008, 7:11:51 AM4/11/08
to
On Apr 11, 12:43 pm, Razii <DONTwhatever...@hotmail.com> wrote:
> On Fri, 11 Apr 2008 01:18:30 -0700 (PDT), asterisc <Rares....@ni.com>

What's the point allocating 1.000.000 new objects and never use them?

Why doesn't Java optimize this and allocate nothing, since they are
not used?

Anyway, in C++ it's a good idea to create memory pools if you intend
to play with a lot of small objects. Something like Ian did.

Try creating a memory pool in Java and compare it with GC's
performance.

Can you overwrite the new operator in Java?
Or are you comparing std::new with Java's new?

You forget that Java's GC is implemented in a lower-level programming
language, as C or C++. It cannot be faster than an implementation in C/
C++.

Sam

unread,
Apr 11, 2008, 7:12:48 AM4/11/08
to
Razii writes:

> On Thu, 10 Apr 2008 21:29:44 -0500, Sam <s...@email-scan.com> wrote:
>
>>See how well /that/ benchmarks against Java :-)
>
>
> That is not the topic. The topic is how the keyword "new" behaves.
>
> 0x12ff5c
> 0x12ff5c
> 0x12ff5c
> Time: 62 ms

See -- C++ is faster than Java. And the topic isn't how the keyword "new"
behaves, but, as it says, “java vs c++ difference in "new" ”. Which, of
course, includes the fact that their respective usage cases are completely
different, and a straight, linear comparison of the kind you made is
meaningless. In C++, objects are allocated on the heap, via new, much less
frequently than in Java, so a one-to-one benchmarking tells you very little.
I pointed out that in many instances C++ objects are instantiated on the
stack, which incurs much less overhead than "new". Furthermore, you don't
even have to use "new" to allocate objects on the heap anyway, in C++.

Take /that/ one for a spin, and see what happens.

> All the references are the same -- not the same output as in the last
> version (or java version).

In your Java version, you added a newline at the end of every print
statement. In your original C++ version, you printed the pointer value
without a trailing newline. I fixed it for you. That's why the output is
different.

James Kanze

unread,
Apr 11, 2008, 7:50:10 AM4/11/08
to
On Apr 10, 4:33 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Lloyd Bonafide wrote:
> > How many of you c.l.c++'ers use one, and in what percentage
> > of your projects is one used? I have never used one in
> > personal or professional C++ programming. Am I a holdover
> > to days gone by?

> I have never used a GC for C++, yet in none of my C++ projects
> (professional or hobby) in the last 5+ years have I had a
> memory leak. I often use tools such as valgrind and AQTime to
> check for memory leaks, and they have yet to report any leak.

And I wrote C and assembler for some 20 years before starting in
C++, and I never had a memory leak in them, either. From
experience, I'd say that you can either write correct programs
in any language, or you can't do it in any language. The
question is one of cost. How much effort does it take.

Garbage collection is a tool which reduces the amount of coding
necessary in some specific cases. As such, it would be foolish
not to avail oneself of it when appropriate. And it would be
just as foolish to expect it to suddenly solve all your
problems, just like that.

> There just exists a *style* of programming in C++ which very
> naturally leads to encapsulated, clean and safe code. (This
> style is drastically different from how, for example, Java
> programming is usually done.)

There are many styles of programming, both in C++ and in any
other language. Many of them don't lead to encapsulated, clean
and safe code. A few do. I use very similar styles of
programming in both Java and C++, but I've seen some pretty bad
code in both as well.

Of course, I don't quite see the relevance to garbage collection
in this. Quite obviously, you can write bad code with garbage
collection. And just as obviously, you can write bad code
without garbage collection.

> One situation where GC *might* help a bit is in efficiency if
> you are constantly allocating and deallocating huge amounts of
> small objects in tight loops. 'new' and 'delete' in C++ are
> rather slow operations, and a well-designed GC might speed
> things up.

> However, part of my C++ programming style just naturally also
> avoids doing tons of news and deletes in tight loops (which
> is, again, very different from eg. Java programming where you
> basically have no choice). Thus this has never been a problem
> in practice.

There are applications, of course, where you don't have the
choice; where you're developing dynamic structures (graphs,
etc.). But even there, the real gain is not in runtime (which
will rarely differ more than 10%-15% one way or the other), but
in development time. If the design determines that object
lifetime can be non-determinate, then you don't have to worry
about it when coding.

Obviously, in languages in which every object is allocated
dynamically, such objects are an overwhelming majority---almost
by definition, a value type doesn't have a determinate lifetime.
In C++, typically, objects without a determinate lifetime tend
more to be special cases: value types with variable size, or
which are too expensive to copy, even when you'd like to, or
"agents": small polymorphic objects without much, if any, state,
which are passed around, typically so that an object A can do
something dependent on the actual type of another object B.
While such objects aren't the majority, at least not in most C++
programs, they do occur often enough to make it worth having
garbage collection in your toolkit. Every little bit helps, as
they say.

> Even if I some day stumble across a situation where constant
> allocations and deallocations are impacting negatively the
> speed of a program, and there just isn't a way around it, I
> can use a more efficient allocator than the default one used
> by the compiler. (I have measured speedups to up to over 8
> times when using an efficient allocator compared to the
> default one.)

You seem to be misunderstanding the argument. There are
specific times when garbage collection might be chosen for
performance reasons, but they are fairly rare, and as you say,
you can also optimize the performance of manual schemes. The
main argument for garbage collection is greater programmer
efficiency.

(There is a second argument, involving security. The fact that
the underlying memory of an object cannot be used for any other
object as long as there remains a pointer to the original
object. In an ideal system, of course, there wouldn't be such
pointers. But in practice, it's nice that you can make behavior
defined even if they happen to occur.)

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Juha Nieminen

unread,
Apr 11, 2008, 7:50:56 AM4/11/08
to
Razii wrote:
> Also, according the site
> above, in C++ memory is never returned to the operating system (at
> least the older OS)

Which "older OS"? Some 30yo?

Juha Nieminen

unread,
Apr 11, 2008, 7:53:48 AM4/11/08
to

My point is that the style of C++ programming which produces safe code
tends to also produce good code in other respects as well. Thus there's
a positive side-effect to not having GC in this case.

I often find that even quick&dirty small programs to perform minuscule
tasks look good because of this style of programming, and it doesn't
even necessarily require any extra work (mainly because usually the STL
can be used for data management).

Juha Nieminen

unread,
Apr 11, 2008, 7:57:06 AM4/11/08
to
Razii wrote:
> On Fri, 11 Apr 2008 03:35:27 +0300, Juha Nieminen
> <nos...@thanks.invalid> wrote:

>
>> Razii wrote:
>>> In C++, each "new" allocation request
>>> will be sent to the operating system, which is slow.
>> That's blatantly false.
>
> Well, my friend, I have proven you wrong. Razi has been victorious
> once again :)

Uh? I said that the claim that each "new" performs an OS call is
blatantly false. How does your program prove that wrong?

Your C++ program does *not* perform a system call for each executed
new, and I can prove that.

James Kanze

unread,
Apr 11, 2008, 8:04:53 AM4/11/08
to
On Apr 10, 11:56 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Pascal J. Bourguignon wrote:
> > Now, on another level, I'd say that the problem is that this safe
> > style you must adopt in C++ to avoid memory leaks is a burden that
> > forces you to spend your energy in a sterile direction.

> I strongly disagree. This style of programming almost
> automatically leads to a clean, abstract, encapsulated design,
> which is only a good thing.

We must have had to maintain C++ code written by different
people:-). I don't think you can really claim that C++ forces
you to write clean, abstract, encapsulated code. (Nor does
Java, of course. Or any other language.)

> Programmers using languages with GC (such as Java) might not need to
> worry about where their dynamically-allocated memory is going, but
> neither do I, in most cases. I even dare to claim that at least in some
> cases this style of modular programming produces cleaner, simpler, more
> understandable and in some cases even more efficient code than a
> "mindlessly use 'new' everywhere" style of programming.

Woah. Garbage collection has absolutely nothing to do with how
often you use new. In fact, in many cases, it will result in a
lot less use of new than otherwise. It's much easier to share
representations if you don't have to worry about who's going to
delete it.

> I honestly don't feel that I need to put any extra effort to
> produce this kind of safe and clean code. Given that I usually
> like the end result as a design, even if I have to put that
> bit of extra effort it's totally worth it.

> > More dynamic languages, with a garbage collector, are
> > liberating your mind, so your free neurons can now think
> > about more interesting software problems (like for example,
> > AI, or providing a better user experience, etc).

> I have my doubts that this "liberating" style of programming
> somehow automatically leads to clean, modular and abstract
> designs. All the contrary, I would even claim that at least in
> some cases it leads to the opposite direction ("reckless
> programming").

The whole argument is irrelevant. On both sides. Garbage
collection doesn't make a language "dynamic", at least not in
the usual sense. Weak typing does, and I would agree that most
of the time, this leads to less robust code. The fact that
everything derives from Object (or rather, that so many things
only know about Object) is a disaster when it comes to writing
robust code. But you can do this in C++ as well---some early
container libraries did. (I believe that the problems revealed
by such libraries were part of the motivation for adding
templates to the language. Although even before templates, many
of us found that using <generic.h>, as painful as that was, was
preferable to "everything is an Object".)

In practice (and I speak here from experience), using garbage
collection in C++ doesn't impact style that much. (And with the
exception of a few people like you and Jerry Collins, many of
those worried about its impact on style really do need to change
their style.) Even with garbage collection, the "default" mode
in C++ is values, not references or pointers (call them whatever
you want), with true local variables, on the stack, and not
dynamically allocated memory. As far as I know, there's never
been the slightest suggestion that this should be changed.

The result is that, unlike the case in Java, garbage collection
isn't necessary in C++. But it does save some effort in certain
cases. And it can be used to significantly enhance security in
others. (Dangling pointers can be a serious security problem,
see
http://searchsecurity.techtarget.com/news/article/0,289142,sid14_gci1265116,00.html.
And while garbage collection can't completely eliminate dangling
pointers in C++---you can still return a pointer to a local
variable---it can certainly help.)

Juha Nieminen

unread,
Apr 11, 2008, 8:02:55 AM4/11/08
to
Razii wrote:
> On Fri, 11 Apr 2008 03:35:53 GMT, "Mike Schilling"
> <mscotts...@hotmail.com> wrote:
>
>> And you're wrong, as has been demonstrated repeatedly. There's no
>> point trying to explain this any further.
>
> There was nothing wrong with my basic premise that creating objects
> with on heap is much faster in java than in c++. Google search
> confirms..

Your quote confirms that your claim that each 'new' causes an OS call
is false.

Message has been deleted

Juha Nieminen

unread,
Apr 11, 2008, 8:05:47 AM4/11/08
to
Razii wrote:
> That is not the topic. The topic is how the keyword "new" behaves.

You just don't get it, do you. Your original claim was that "new" in
C++ is slow "because each new calls the OS". That's just false. Each
"new" does *not* call the OS.

James Kanze

unread,
Apr 11, 2008, 8:11:20 AM4/11/08
to
On Apr 11, 1:53 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Matthias Buelow wrote:
> > Juha Nieminen wrote:

> >> I have my doubts that this "liberating" style of programming somehow
> >> automatically leads to clean, modular and abstract designs. All the
> >> contrary, I would even claim that at least in some cases it leads to the
> >> opposite direction ("reckless programming").

> > And your point is? The simple fact is, that bad programmers
> > write bad code, and good programmers write good code, no
> > matter what the language is or whether memory is managed
> > automatically or manually.

> My point is that the style of C++ programming which produces
> safe code tends to also produce good code in other respects as
> well. Thus there's a positive side-effect to not having GC in
> this case.

That's a non sequitur. The style of Java programming which
produces safe code also tends to produce good code in other
respects as well. Globally, it's probably more difficult to
produce safe code in Java than in C++, but this is despite
garbage collection, not because of it. (In really safe code,
for example, public functions are almost never virtual, unless
the language has some sort of built-in support for PbC, a la
Eiffel. And of course, safe code is best served by strict type
checking---none of this "everything is an Object" business.)

Juha Nieminen

unread,
Apr 11, 2008, 8:16:07 AM4/11/08
to
James Kanze wrote:
> You seem to be misunderstanding the argument. There are
> specific times when garbage collection might be chosen for
> performance reasons, but they are fairly rare, and as you say,
> you can also optimize the performance of manual schemes. The
> main argument for garbage collection is greater programmer
> efficiency.

I understood the argument, and I already said that I don't feel I'm
programming inefficiently. The style of safe modular C++ programming
tends to produce clean designs. In many cases this is *not* at the cost
of increased development time.
In fact, if you can reuse your previously created modular code, the
development time may even decrease considerably. In my experience Java
tends to lead to "reckless programming" ("why should I encapsulate when
there's no need? the GC is handling everything"), which often doesn't
produce reusable code, so in the long run it may even be
counter-productive with respect to development times.

Pascal J. Bourguignon

unread,
Apr 11, 2008, 8:21:26 AM4/11/08
to
James Kanze <james...@gmail.com> writes:

Do you mean that in Java, once you've defined a method zorglub on a
class A, since everything is an object, you can send the messaeg
zorglub on an instance of the class B that is not a subclass of A?


--
__Pascal Bourguignon__

James Kanze

unread,
Apr 11, 2008, 8:26:21 AM4/11/08
to
On Apr 11, 2:06 pm, r...@zedat.fu-berlin.de (Stefan Ram) wrote:
> Juha Nieminen <nos...@thanks.invalid> writes:
> >I don't see how this is so much different from what Java does.

> »[A]llocation in modern JVMs is far faster than the best
> performing malloc implementations. The common code path
> for new Object() in HotSpot 1.4.2 and later is
> approximately 10 machine instructions (data provided by
> Sun; see Resources), whereas the best performing malloc
> implementations in C require on average between 60 and 100
> instructions per call (Detlefs, et. al.; see Resources).
> And allocation performance is not a trivial component of
> overall performance -- benchmarks show that many
> real-world C and C++ programs, such as Perl and
> Ghostscript, spend 20 to 30 percent of their total
> execution time in malloc and free -- far more than the
> allocation and garbage collection overhead of a healthy
> Java application (Zorn; see Resources).«

Just for the record, this is typical market people speak.

First, of course, it's well known that an allocation in a
compacting garbage collector can be significantly faster than in
any non-compacting scheme (for variable length allocations).
It's also well known that the actual garbage collection sweep in
a compacting collector is more expensive than in a
non-compacting one. You don't get something for nothing.
Whether the trade off is advantages depends on the application.
(I suspect that there are a lot of applications where the
tradeoff does favor compacting, but there are certainly others
where it doesn't, and only talking about the number of
machine instructions in allocation, without mentionning other
costs, is disingenuous, at best.)

Secondly, I've written C++ programs which spend 0% of their
total execution time in malloc and free, and I've had to fix one
which spent well over 99.9% of its time there. With such
variance, "average" looses all meaning. And the choice of Perl
and Ghostscript as "typical" C++ programs is somewhat
disingenuous as well; both implement interpreters for languages
which use garbage collection, so almost by definition, both
would benefit from garbage collection. (In fact, both probably
implement it somehow internally, so the percentage of time spent
in malloc/free is that of a garbage collected program.)

James Kanze

unread,
Apr 11, 2008, 8:30:07 AM4/11/08
to
On Apr 11, 3:07 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> "Razii" <DONTwhatever...@hotmail.com> wrote in message

> news:v5btv3lmqeknq5imt...@4ax.com...

> > On Thu, 10 Apr 2008 17:33:21 +0300, Juha Nieminen
> > <nos...@thanks.invalid> wrote:

> >> However, part of my C++ programming style just naturally also avoids
> >>doing tons of news and deletes in tight loops (which is, again, very
> >>different from eg. Java programming where you basically have no choice)

> > Howeever, Java allocates new memory blocks on it's internal
> > heap (which is allocated in huge chunks from the OS). In
> > this way, in most of the cases it bypasses memory allocation
> > mechanisms of the underlying OS and is very fast. In C++,


> > each "new" allocation request will be sent to the operating
> > system, which is slow.

> You are incorrect. Each call into "new" will "most-likely" be
> "fast-pathed" into a "local" cache.

Are you sure about the "most-likely" part? From what little
I've seen, most C runtime libraries simply threw in a few locks
to make their 30 or 40 year old malloc thread safe, and didn't
bother with more. Since most of the marketing benchmarks don't
use malloc, there's no point in optimizing it. I suspect that
you're describing best practice, and not most likely. (But I'd
be pleased to learn differently.)

Matthias Buelow

unread,
Apr 11, 2008, 8:37:44 AM4/11/08
to
Juha Nieminen wrote:

> I understood the argument, and I already said that I don't feel I'm
> programming inefficiently. The style of safe modular C++ programming
> tends to produce clean designs.

"The style of safe modular XYZ programming tends to produce clean
designs". Valid for any language. The thing is, even if you(r
programmers) have the time and expertise to produce such a shiny clean
design, it won't stay that way. You have to plan for the worst case,
which is, your program will degenerate into a nasty mess, which is
usually the case, over time.

> In many cases this is *not* at the cost of increased development time.

If you use a relatively low-level language such as C++, this certainly
_does_ effect your productivity. I can't understand where you get the
idea that it doesn't. A more expressive language, preferrably one
designed for or adaptable to the problem domain, will in many cases
produce a dramatic improvement in productivity over the kind of manual
stone-breaking one is doing in C++. High-level languages and
domain-specific languages are usually implemented with automatic memory
management because of the more abstract programming models being used.
You can design and write the cleanest, shiniest modular C++ code, some
mediocre programmer using a language that is more expressive for the
task at hand will beat you hands down. Maybe the reason why, as you
allege, some kind of "strict discipline" yields better results in C++ is
because this is the case for tasks where the language isn't that well
suited for, and one simply needs this discipline, otherwise one cannot
get useful results.

lbon...@yahoo.com

unread,
Apr 11, 2008, 8:38:55 AM4/11/08
to

But when Sun's marketing tells bad programmers they don't have to
worry abour memory anymore, it's a disaster. They do have to worry,
just in a different way.

James Kanze

unread,
Apr 11, 2008, 8:41:27 AM4/11/08
to
On Apr 11, 2:16 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> James Kanze wrote:
> > You seem to be misunderstanding the argument. There are
> > specific times when garbage collection might be chosen for
> > performance reasons, but they are fairly rare, and as you say,
> > you can also optimize the performance of manual schemes. The
> > main argument for garbage collection is greater programmer
> > efficiency.

> I understood the argument, and I already said that I don't
> feel I'm programming inefficiently. The style of safe modular
> C++ programming tends to produce clean designs. In many cases
> this is *not* at the cost of increased development time.

But how is this relevant to garbage collection. Safe, modular
programming will reduce development times in all cases.

> In fact, if you can reuse your previously created modular
> code, the development time may even decrease considerably.

Certainly. The large standard library is certainly a plus for
Java.

> In my experience Java tends to lead to "reckless programming"
> ("why should I encapsulate when there's no need? the GC is
> handling everything"), which often doesn't produce reusable
> code, so in the long run it may even be counter-productive
> with respect to development times.

What does encapsulation have to do with garbage collection?
That's what I don't understand. Encapsulation is encapsulation.
It's a must, period. If I were to judge uniquely by the code
I've actually had to work on, I'd have to say that encapsulation
was better in Java. In fact, I know that you can do even better
in C++, despite the way some people program in C++. And I know
that the one Java project I worked on was an exception (in
general, not just as a Java project) in that it was well
managed, and that encapsulation was an important issue up front,
and that some Java programmers tend to ignore it.

If there's a difference, I'd say that it is more related to the
size of the projects in each language. In small projects,
there's less organization, and more temptation to just ignore
the rules. And for reasons which have nothing to do with
garbage collection, Java doesn't scale well to large projects,
and tends to be used for small, short lived projects. But that
has nothing to do with garbage collection.

Matthias Buelow

unread,
Apr 11, 2008, 8:44:50 AM4/11/08
to
lbon...@yahoo.com wrote:

> But when Sun's marketing tells bad programmers they don't have to
> worry abour memory anymore, it's a disaster. They do have to worry,
> just in a different way.

Well... "marketing"... "bad programmers"...

Perhaps some of the more simple-minded specimens of "decision makers"
believe that Sun has solved the "memory problem". Maybe some of the less
experienced programmers believe that, too. However, that's not a problem
with automatic memory management or indeed any other technical issue.
You can't even blame Sun's marketing, it's their job, more or less.

Message has been deleted

James Kanze

unread,
Apr 11, 2008, 8:55:03 AM4/11/08
to
On Apr 11, 2:37 pm, Matthias Buelow <m...@incubus.de> wrote:
> Juha Nieminen wrote:
> > I understood the argument, and I already said that I don't feel I'm
> > programming inefficiently. The style of safe modular C++ programming
> > tends to produce clean designs.

> "The style of safe modular XYZ programming tends to produce clean
> designs". Valid for any language. The thing is, even if you(r
> programmers) have the time and expertise to produce such a shiny clean
> design, it won't stay that way. You have to plan for the worst case,
> which is, your program will degenerate into a nasty mess, which is
> usually the case, over time.

That's a self fulfilling prophecy. The moment you plan to
produce a nasty mess, you will. What you should do is organize
the projects so that they don't degenerate into a nasty mess.
I've worked on one or two C++ projects where the quality of the
code actually improved each iteration.

> > In many cases this is *not* at the cost of increased
> > development time.

> If you use a relatively low-level language such as C++, this
> certainly _does_ effect your productivity.

If you insist on using the low-level features where they aren't
appropriate, this will definitely have a negative effect on your
productivity. But so will programming in Java without using the
standard library components (except those in java.lang). Modern
languages tend to be more or less modular, with more and more
abstraction pushed off into the library. C++ is an extreme case
in this regard.

> I can't understand where you get the idea that it doesn't. A
> more expressive language, preferrably one designed for or
> adaptable to the problem domain, will in many cases produce a
> dramatic improvement in productivity over the kind of manual
> stone-breaking one is doing in C++.

Unless you're writing low level libraries, you're not doing
manual stone-breaking in C++. The actual coding I did in Java
was much lower level that what I currently do in C++ (but I've
also done very low level coding in C++).

> High-level languages and domain-specific languages are usually
> implemented with automatic memory management because of the
> more abstract programming models being used.

Modern languages generally provide automatic memory management,
because it is something that can be automated efficiently. It's
helps, but it's not a silver bullet. And of course, some of us
regularly use automatic memory management in C++. Because C++
has value semantics, it's not as essential as in Java, but it
helps.

> You can design and write the cleanest, shiniest modular C++
> code, some mediocre programmer using a language that is more
> expressive for the task at hand will beat you hands down.

Care to bet. Say, write some nice, simple to use components
which use complex arithmetic. (In this case, of course, the
difference isn't garbage collection, but operator overloading.
A necessity in any modern language, but missing in Java, or at
least, it was missing when I used Java.)

> Maybe the reason why, as you allege, some kind of "strict
> discipline" yields better results in C++ is because this is
> the case for tasks where the language isn't that well suited
> for, and one simply needs this discipline, otherwise one
> cannot get useful results.

In general, a strict discipline is necessary in all programming.
I suspect that Juha's argument is that without this strict
discipline, a C++ program will typically crash (which generally
doesn't go unnoticed), where as a Java program will just give
wrong results. I disagree with his conclusions for several
reasons: most significantly, because with garbage collection in
C++, you can better guarantee the crashes, but also because I
don't see why good programmers should be deprived of a useful
tool simply because there are so many bad programmers around.
But the argument that strict discipline is good can't be
disputed.

Lew

unread,
Apr 11, 2008, 9:25:43 AM4/11/08
to
Juha Nieminen wrote:
> Razii wrote:
>> That is not the topic. The topic is how the keyword "new" behaves.
>
> You just don't get it, do you.

Don't feed the trolls. Especially don't feed them by being trollish in return.

--
Lew

Lew

unread,
Apr 11, 2008, 9:29:59 AM4/11/08
to
Chris Thomasson wrote:
>> Before I answer you, please try and answer a simple question:
>>
>> If thread A allocates 256 bytes, and thread B races in and
>> concurrently attempts to allocate 128 bytes... Which thread is going
>> to win?

Both threads.

The semantics of the Java language guarantee that both allocations will
succeed. The JVM will not experience a race condition.

> Oh yeah... Thread C tries to allocate just before thread B...
>
>
> Which thread is going to win?

All three.

> Thing of how a single global pointer to a shared virtual memory range
> can be distributed and efficiently managed...

*What* "global pointer" are you talking about? There is no "global pointer"
involved in Java's 'new' operator, at least not one that we as developers will
ever see. That is a detail of how the JVM implements 'new', and is of no
concern whatsoever at the language level.

FWIW, AIUI, each thread gets a local chunk of memory from which it allocates
its objects. Whether that's the technique any particular JVM uses is highly
irrelevant. What's important is that the semantics of the language makes
promises about the thread safety of construction.

<http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html>

--
Lew

Razii

unread,
Apr 11, 2008, 4:47:32 PM4/11/08
to
On Fri, 11 Apr 2008 09:25:43 -0400, Lew <l...@lewscanon.com> wrote:

>Don't feed the trolls. Especially don't feed them by being trollish in return.

*PLONK*

Razii

unread,
Apr 11, 2008, 5:08:05 PM4/11/08
to
On Fri, 11 Apr 2008 04:11:51 -0700 (PDT), asterisc <Rare...@ni.com>
wrote:

>What's the point allocating 1.000.000 new objects and never use them?

Huh? The point is to benchmark the speed of creating objects with the
operator new and compare it with C++ version. it's about 10 times
faster than in c++.

>Why doesn't Java optimize this and allocate nothing, since they are
>not used?

They are used as you are printing them in the loop with i % 500000.
Why doesn't the C++ compiler optimize them?

>Can you overwrite the new operator in Java?
>Or are you comparing std::new with Java's new?

Why would I want to do something as stupid as overwrite new operator?

>You forget that Java's GC is implemented in a lower-level programming
>language, as C or C++. It cannot be faster than an implementation in C/
>C++.

It's irrelevant what language is used to write compilers/VM or GC. The
speed of execution depends on the code produced and the design of the
language. If you retrofit C++ with GC using a library, you can't use
optimizations that require the compiler to know the details of the
memory al locator and collector, i.e. the GC. This is not possible if
the GC has been retrofitted onto the language as a library. The
compiler's optimizer does not have the necessary information to make
the optimizations.

"Because it is hard to move objects for C programs", i.e. retrofitting
limits choices which limits performance.

"Many Java/ML/Scheme implementations have faster garbage collectors
that may move objects..." - Hans Boehm
http://www.hpl.hp.com/personal/Hans_...l/slide_4.html

Razii

unread,
Apr 11, 2008, 5:44:28 PM4/11/08
to

How about mobile and embedded devices that don't have sophisticated
memory management? If a C++ application is leaking memory, the memory
might never be returned even after the application is terminated.
This is more dangerous than memory leak in Java application, where,
after the application is terminated, all memory is returned by VM.


Ian Collins

unread,
Apr 11, 2008, 5:48:47 PM4/11/08
to
Razii wrote:
> On Fri, 11 Apr 2008 14:50:56 +0300, Juha Nieminen
> <nos...@thanks.invalid> wrote:
>
>>> Also, according the site
>>> above, in C++ memory is never returned to the operating system (at
>>> least the older OS)
>> Which "older OS"? Some 30yo?
>
> How about mobile and embedded devices that don't have sophisticated
> memory management?

It's not uncommon for such devices to use a static design, so there's no
chance of a leak.

> If a C++ application is leaking memory, the memory
> might never be returned even after the application is terminated.

You'd be surprised how much effort goes into memory management on
embedded devices. Memory is a more precious commodity in the embedded
world.

--
Ian Collins.

Patricia Shanahan

unread,
Apr 11, 2008, 6:48:36 PM4/11/08
to
Razii wrote:
> On Thu, 10 Apr 2008 20:37:59 -0500, Razii
> <DONTwha...@hotmail.com> wrote:
>
>> int main(int argc, char *argv[]) {
>>
>> clock_t start=clock();
>> for (int i=0; i<=10000000; i++) {
>> Test *test = new Test(i);
>> if (i % 5000000 == 0)
>> cout << test;
>> }
>
> If I add delete test; to this loop it gets faster. huh? what the
> exaplanation for this?
>
> 2156 ms
>
> and after I add delete test; to the loop
>
> 1781 ms
>
> why is that?

Due to caching at various levels of the memory hierarchy, accesses to
recently referenced virtual addresses are often a lot faster than
accesses to new ones. The original C++ code requested 10,000,000
distinct Test-sized memory allocations with no reuse. With "delete
test;" the memory allocator can reissue the same piece of memory for
each "new" operation.

In addition, the sheer amount of memory being allocated in the original
C++ program may have required some system calls to get additional
allocatable memory.

The JVM is free to reuse the virtual memory previously occupied by an
unreachable Test object, so the version with "delete test;" is a bit
more comparable to the Java program.

This illustrates the basic problem with snippet benchmarks. In modern
computers the performance of small operations depends on their context.
Taking them out of context is not realistic.

Patricia

Juha Nieminen

unread,
Apr 11, 2008, 6:51:31 PM4/11/08
to
Stefan Ram wrote:
> »Your essay made me remember an interesting phenomenon I
> saw in one system I worked on. There were two versions of
> it, one in Lisp and one in C++. The display subsystem of
> the Lisp version was faster. There were various reasons,
> but an important one was GC: the C++ code copied a lot of
> buffers because they got passed around in fairly complex
> ways, so it could be quite difficult to know when one
> could be deallocated. To avoid that problem, the C++
> programmers just copied.

I suppose you can compare incompetent C++ programmers with lisp
programmers (in the sense that lisp may lead, by its very nature, to
efficient code without the need to create complicated designs). However,
generalizing from this that lisp produces faster code than C++ is a bit
unfair.

> A lot of us thought in the 1990s that the big battle would
> be between procedural and object oriented programming, and
> we thought that object oriented programming would provide
> a big boost in programmer productivity. I thought that,
> too. Some people still think that. It turns out we were
> wrong. Object oriented programming is handy dandy, but
> it's not really the productivity booster that was
> promised. The real significant productivity advance we've
> had in programming has been from languages which manage
> memory for you automatically.

Claiming that OOP has not improved productivity significantly is quite
far-fetched.

(Personally I feel there has been a counter-movement against OOP: In
the late 80's and early 90's OOP was the fad and the extreme hype. While
it did indeed improve productivity a lot, it was not, however, the final
silver bullet. In other words, in some ways it was a bit of a
disappointment after all that hype. This produced an odd
counter-reaction in some circles who, for some reason, can only see what
OOP did *not* deliver and close their eyes to all that it did. It's a
kind of anti-hype as a post-reaction to the hype. IMO this kind of
counter-movement is stupid and misguided.)

It is loading more messages.
0 new messages