Actually, it is. Since you can't allocate object on the stack (like you can with C++), everything is allocated on the heap. If you are continuously allocating and deallocating heap memory, it will actually add quite a bit of overhead (as well as possibly fragmenting the heap). We've done quite a bit of GC tuning at work, and it's amazing the performance difference you can get just by adjusting how much memory the GC has to work with (more memory means fewer allocations/deallocations).
Maybe back in like 1969 that would have been an issue (but then again, maybe not). These days, though, I would hardly consider it a major bottleneck for most applications. Maybe the GC is implemented poorly - I don't know - but what I can tell you is that you can write a C program that calls malloc/free in a tight loop and see quite satisfactory performance (for most implementations, anyway). That is enough to tell me that it most certainly can be efficient if designed properly.
I think the issue is not problematic, Sebastiani. The language idioms adjust to each other and you will be given the needed tools to code under a non-deterministic destructors environment. That is, lack of a deterministic destructor won't stop good and efficient code from being written in Java. Neither it hinders in any way the ability of the language to provide usable software.
Well sure, good programmers learn how to deal with these things, naturally. I'm just saying that I'm not enjoying it one bit. It's a pain in the arse, pure and simple.
When you consider all the extra work besides just setting a memory space for an object, it can become expensive. Member initialization can be an expensive proposal and I wouldn't be surprised (I don't know Java that well) if the JVM takes advantage of exactly this to enable member initialization shortcuts.
I don't know what shortcuts you're alluding to, but I'm betting the perfomance difference is effectively negligible.
Can it be that we sometimes confuse our personal preferences with the notion of right and wrong?
Nope. Let me use an example that I think I've used before. Consider this very simple class:
Code:
struct tag_writer
{
tag_writer( string const& name )
: name( name )
{
cout << "<" << name << ">" << endl;
}
virtual ~tag_writer( void )
{
cout << "</" << name << ">" << endl;
}
string
name;
};
int main( void )
{
tag_writer
a( "a" ),
b( "b" ),
c( "c" ),
d( "d" ),
e( "e" ),
f( "f" ),
g( "g" ),
h( "h" ),
i( "i" ),
j( "j" ),
k( "k" ),
l( "l" ),
m( "m" ),
n( "n" ),
o( "o" ),
p( "p" ),
q( "q" ),
r( "r" ),
s( "s" ),
t( "t" ),
u( "u" ),
v( "v" ),
w( "w" ),
x( "x" ),
y( "y" ),
z( "z" );
return 0;
}
Now, just write a program in Java that produces the same output! See my point? And this is a trivial example - the reality is that deterministic destructors create all sorts of opportunities that just aren't possible (without a lot of effort, anyway) otherwise.