Object instantiation and garbage collection

M

Mario

What's more efficient from a performance/garbage collection point of
view - assigning an object to a variable or not?

Eg:
public class Test {

public void method1() {

Employees e = new Employees();
List l = e.getNames();
}

public void method2() {

List l = (new Employees).getNames();
}
}
 
S

Steve W. Jackson

Mario said:
What's more efficient from a performance/garbage collection point of
view - assigning an object to a variable or not?

Eg:
public class Test {

public void method1() {

Employees e = new Employees();
List l = e.getNames();
}

public void method2() {

List l = (new Employees).getNames();
}
}

In your first example, the compiler is most likely savvy enough to
optimize out the variable "e". But the result is still the same: the
Employees object goes out of scope immediately after calling its
getNames() method and is therefore eligible for collection. That's
assuming, of course, that you correct the flaw in method2 which would
prevent the above from even compiling.

= Steve =
 
M

Mario

Sorry - I forgot to complete the question! : given that both method 1
and 2 work, which one is more efficient?

In m1, "new Employees()" is assigned a reference, in m2 it's not.
So, will garbage collection kick in faster in m2 since there is no
reference to Employees?
 
E

Eric Sosman

Mario said:
What's more efficient from a performance/garbage collection point of
view - assigning an object to a variable or not?

Eg:
public class Test {

public void method1() {

Employees e = new Employees();
List l = e.getNames();
}

public void method2() {

List l = (new Employees).getNames();
}
}

In this simple example there will probably be no discernible
difference -- certainly no different worth worrying about. In
method2 the Employees object may become collectible about 1.642
nanoquivers sooner than in method1, but you'll never notice it.

In order to see (or have a chance of seeing) any difference
you need something like

void method3() {
Employees e = new Employees();
List l = e.getNames();
someCalculationThatTakesLotsOfTime();
}

Here, the Employees object remains uncollectible as long as `e'
survives, so if it isn't needed during someCalculation... you
are "wasting" memory for that period of time. However, even
this isn't likely to make much trouble unless someCalculation...
really does take LotsOfTime *and* an Employees object (and any
other objects it "owns") take up a lot of memory. *If* both of
these are true, you may get some benefit from the method2 way
of doing things, or by writing `e = null;' once you're through
with the object.

IMHO, people worry about this more than is needful. That's
not to say there isn't a potential problem, just that the problem
isn't as prevalent as fear makes it seem. Do you check for
cobras under your bed every night?
 
S

Stefan Schulz

In order to see (or have a chance of seeing) any difference
you need something like

void method3() {
Employees e = new Employees();
List l = e.getNames();
someCalculationThatTakesLotsOfTime();
}

Even here, e might already be collected while the calculation
is still running, if the bytecode interpreter is smart enough to realize
that both l and e are no longer live when the calculation started (since
they are never again referenced)
 
E

Eric Sosman

Stefan said:
Even here, e might already be collected while the calculation
is still running, if the bytecode interpreter is smart enough to realize
that both l and e are no longer live when the calculation started (since
they are never again referenced)

Yes; that's why I wrote "(or have a chance of seeing)."
It is possible to get into trouble by hanging on to objects
long after they're needed, but this isn't usually the way
it happens.
 
J

Joan

Mario said:
What's more efficient from a performance/garbage collection point of
view - assigning an object to a variable or not?

Eg:
public class Test {

public void method1() {

Employees e = new Employees();
List l = e.getNames();
}

public void method2() {

List l = (new Employees).getNames();
}
}

In the 1970's when the user was learning about optimization of programming
languages, there was an optimization technique that if applied to you
example,
would not create a local variable for "e" at all. The code generated by the
compiler
would be the same for the two methods.

You should compile it and see what's generated by Java and let us know.
 
C

cbongior

Mario,

Garbage collection is NON-deterministic. The question of asking which
one is "efficient from a performance/garbage collection point of
view" implies some concept of determinism. Besides the fact that the
JavaVM specification does not require any sort of determinism on GC,
the GC is a background Thread. Threads are non-deterministic and
therefore any actions they take are also non-deterministic.

This lack of determinism is is big hurdle for java in the Realtime
(especially hard-realtime) computing realm where this lack of
predictability simply causes Java to be unacceptable for these
platforms. If micro (or even milli) seconds are the determining factor
between life and death, the last thing you want you app doing is
deciding that now would be a good time to clean up memory!

This all goes to realtime system design -- out of the scope of this
discussion.

Christian
http://christian.bongiorno.org/resume.pdf
 
A

Andrew McDonagh

Joan said:
In the 1970's when the user was learning about optimization of programming
languages, there was an optimization technique that if applied to you
example,
would not create a local variable for "e" at all. The code generated by the
compiler
would be the same for the two methods.

You should compile it and see what's generated by Java and let us know.

Here's the byte code using java 1.4.2_08....

C:\eclipse\workspace\test\bin>javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #9; //Method java/lang/Object."<init>":()V
4: return

public void method1();
Code:
0: new #16; //class Employees
3: dup
4: invokespecial #17; //Method Employees."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #21; //Method Employees.getNames:()Ljava/util/List;
12: astore_2
13: return

public void method2();
Code:
0: new #16; //class Employees
3: dup
4: invokespecial #17; //Method Employees."<init>":()V
7: invokevirtual #21; //Method Employees.getNames:()Ljava/util/List;
10: astore_1
11: return

}
 
J

Joan

Andrew McDonagh said:
Here's the byte code using java 1.4.2_08....

C:\eclipse\workspace\test\bin>javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #9; //Method java/lang/Object."<init>":()V
4: return

public void method1();
Code:
0: new #16; //class Employees
3: dup
4: invokespecial #17; //Method Employees."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #21; //Method Employees.getNames:()Ljava/util/List;
12: astore_2
13: return

public void method2();
Code:
0: new #16; //class Employees
3: dup
4: invokespecial #17; //Method Employees."<init>":()V
7: invokevirtual #21; //Method Employees.getNames:()Ljava/util/List;
10: astore_1
11: return

}

Ok, two comments that come to mind.

1. For method1 a peephole optimizer would recognize the
astore_1 followed by aload_1 and delete the aload_1, maybe it could
recognize that this variable is not used in the method and get rid of the
astore_1 too.

2. I don't know the name of it, but some optimization should get rid of
the astore_1 or astore_2 just before 'return' in both methods since it is a
local
and disappears when the return is executed.

It actually looks like NO optimization is done.
 
T

Thomas G. Marshall

Stefan Schulz coughed up:
Even here, e might already be collected while the calculation
is still running, if the bytecode interpreter is smart enough

If this is the extent to which Employees is used, then the /compiler/ really
ought to be smart enough to generate identical bytecodes for

A a = new A();
B = a.m();

and

B = (new A()).m();

I'd be disapointed if it isn't. The bytecode interpreter should not enter
into this at all.

....[rip]...
 
T

Thomas G. Marshall

Thomas G. Marshall coughed up:
Stefan Schulz coughed up:
Even here, e might already be collected while the calculation
is still running, if the bytecode interpreter is smart enough

If this is the extent to which Employees is used, then the /compiler/
really ought to be smart enough to generate identical bytecodes for

A a = new A();
B = a.m();

and

B = (new A()).m();

I'd be disapointed if it isn't. The bytecode interpreter should not
enter into this at all.

...[rip]...


Sorry for this-----I hadn't noticed that this was discussed further already
downthread.
 
S

Stefan Schulz

If this is the extent to which Employees is used, then the /compiler/ really
ought to be smart enough to generate identical bytecodes for

A a = new A();
B = a.m();

and

B = (new A()).m();

I'd be disapointed if it isn't. The bytecode interpreter should not enter
into this at all.

I'd be disappointed if the bytecode was identical, actually. Bytecode
should mirror sourcecode to the closest extend possible. Think about a
debugger, or some disassembly tool.

Since the final compilation steps are done later, we can afford not to
produce ideal, optimized code, and gain much better debug facilities.
 
S

Stefan Schulz

1. For method1 a peephole optimizer would recognize the
astore_1 followed by aload_1 and delete the aload_1, maybe it could
recognize that this variable is not used in the method and get rid of the
astore_1 too.

2. I don't know the name of it, but some optimization should get rid of
the astore_1 or astore_2 just before 'return' in both methods since it is a
local
and disappears when the return is executed.

It actually looks like NO optimization is done.

Which is just as well, since when i clamp that class up my debugger, i
want to see the local variable. Maybe i introduced it just for looking
into the object, and examining its state before it is used in the other
call.
 
T

Tor Iver Wilhelmsen

Mario said:
In m1, "new Employees()" is assigned a reference, in m2 it's not.
So, will garbage collection kick in faster in m2 since there is no
reference to Employees?

No; in both cases it is a reference on the stack, except in the first
case that reference is copied to a "named" slot as well.

On exit, all references on the stack go away. Whether there was one or
two pointing at the same object.
 
E

Eric Sosman

Thomas said:
Stefan Schulz coughed up:


If this is the extent to which Employees is used, then the /compiler/ really
ought to be smart enough to generate identical bytecodes for

A a = new A();
B = a.m();

and

B = (new A()).m();

I'd be disapointed if it isn't.


Start weeping ;-) Using 1.4.2_04, the two snippets differ
by two opcodes: one has an astore/aload pair that the other
does not.
The bytecode interpreter should not enter
into this at all.

Maybe not the interpreter per se, but it's certainly
possible that JIT compilation would produce identical native
code. At the least, I'd hope JIT would remove the aload --
of course, the O.P.'s question really comes down to whether
the astore survives.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top