Which is better... performance- and memory-wise?

Discussion in 'Java' started by Rogue Chameleon, Nov 24, 2004.

  1. Hi all

    I've often tossed these two methods of looping through Collections in
    my mind... trying to determine which is the "better solution".

    Thoughts?

    Method 1
    --------
    Object o = null;
    while (i.hasNext()) {
    o = (Object)i.next();
    }

    Method 2
    --------
    while (i.hasNext()) {
    Object o = (Object)i.next();
    }
     
    Rogue Chameleon, Nov 24, 2004
    #1
    1. Advertising

  2. Rogue Chameleon wrote:
    > I've often tossed these two methods of looping through Collections in
    > my mind... trying to determine which is the "better solution".
    >
    > Thoughts?


    There is not difference whatsoever regarding performance and memory;
    both should in fact compile to identical bytecode.

    The second option is better, because it limits variable visibility to
    the smallest scope.
     
    Michael Borgwardt, Nov 24, 2004
    #2
    1. Advertising

  3. Rogue Chameleon

    MaSTeR Guest

    "Michael Borgwardt" <> wrote in message
    news:...
    > Rogue Chameleon wrote:
    > > I've often tossed these two methods of looping through Collections in
    > > my mind... trying to determine which is the "better solution".
    > >
    > > Thoughts?

    >
    > There is not difference whatsoever regarding performance and memory;
    > both should in fact compile to identical bytecode.
    >
    > The second option is better, because it limits variable visibility to
    > the smallest scope.


    The second option is neater and does indeed limits the scope. However I am
    not sure it would compile to the same bytecode (but I might be wrong). Being
    the variable Object (just the pointer I mean) inside a loop wouldn't JVM
    create a new one at each loop ? And if the condition is false at the
    beginning (never goes into the loop) will it be created at all ?
     
    MaSTeR, Nov 24, 2004
    #3
  4. MaSTeR wrote:
    > The second option is neater and does indeed limits the scope. However I am
    > not sure it would compile to the same bytecode (but I might be wrong). Being
    > the variable Object (just the pointer I mean) inside a loop wouldn't JVM
    > create a new one at each loop ?


    No.

    > And if the condition is false at the
    > beginning (never goes into the loop) will it be created at all ?


    Yes.

    Local variables live on the stack, thus they `*must* be known in advance.
    Actually, in byte code, there is no such thing as variable scope either.
     
    Michael Borgwardt, Nov 24, 2004
    #4
  5. Rogue Chameleon

    Chris Uppal Guest

    Michael Borgwardt wrote:

    > > I've often tossed these two methods of looping through Collections in
    > > my mind... trying to determine which is the "better solution".

    > [..]
    >
    > There is not difference whatsoever regarding performance and memory;
    > both should in fact compile to identical bytecode.


    Nitpicking:

    Not /quite/ identical, there's a good chance that the compiler will generate
    explicit bytecode for the assignment in:

    Object o = null;

    IIRC, the java 1.4.x series compilers did so (I haven't yet looked at the
    output from the 1.5.0 compiler in cases like this). Of course, there's then
    the JITer to consider...

    But -- nitpicking aside -- I think it's fair to say that if the
    compiler/runtime ended up producing significantly different runtime behaviour
    for the two loop expressions, then that would be considered a bug.

    -- chris
     
    Chris Uppal, Nov 24, 2004
    #5
  6. Rogue Chameleon wrote:

    > Hi all
    >
    > I've often tossed these two methods of looping through Collections in
    > my mind... trying to determine which is the "better solution".
    >
    > Thoughts?
    >
    > Method 1
    > --------
    > Object o = null;
    > while (i.hasNext()) {
    > o = (Object)i.next();
    > }
    >
    > Method 2
    > --------
    > while (i.hasNext()) {
    > Object o = (Object)i.next();
    > }


    There's no performance difference as others have pointed out, though 2
    is better (unless you actually *need* the binding of "o" outside the
    scope of the iterator).

    But why not:

    for (Iterator i=c.iterator();i.hasNext();)
    Object o = i.next(); // You don't need the coercion for Object

    Of course, in the new Java you should be able to write something like:

    foreach (Object : c)

    Which Java SHOULD have had from the very beginning!

    Dave
     
    Dave Stallard, Nov 24, 2004
    #6
  7. Yeah, I knew that I didn't need to cast (ie. coerce) the Object.... I
    was just using it as a default Class name (instead of using "MyClass").
    Thanks to all for responding...
     
    Rogue Chameleon, Nov 24, 2004
    #7
  8. Rogue Chameleon

    xarax Guest

    "Chris Uppal" <-THIS.org> wrote in message
    news:...
    > Michael Borgwardt wrote:
    >
    > > > I've often tossed these two methods of looping through Collections in
    > > > my mind... trying to determine which is the "better solution".

    > > [..]
    > >
    > > There is not difference whatsoever regarding performance and memory;
    > > both should in fact compile to identical bytecode.

    >
    > Nitpicking:
    >
    > Not /quite/ identical, there's a good chance that the compiler will generate
    > explicit bytecode for the assignment in:
    >
    > Object o = null;
    >
    > IIRC, the java 1.4.x series compilers did so (I haven't yet looked at the
    > output from the 1.5.0 compiler in cases like this). Of course, there's then
    > the JITer to consider...


    Actually, earlier compilers did NOT generate the
    assignment, because the compiler noticed that the
    initial value was the same as the default value.

    That was considered a compiler defect and it was
    fixed. The problem was discovered when trying to
    set a breakpoint on the statement, which never
    triggered, because no code had been generated
    for the statement. Explicit assignments are now
    always generated, regardless of the value.

    Also, JIT'd code is supposedly debuggable now, so
    an explicit assignment of a default value should
    not get optimized away by the JIT.

    > But -- nitpicking aside -- I think it's fair to say that if the
    > compiler/runtime ended up producing significantly different runtime behaviour
    > for the two loop expressions, then that would be considered a bug.


    That's a fair statement. It is quite likely that the stack
    frame slot for the local variable "o" would be same in either
    example. Therefore, the generated bytecode should appear
    identical for both examples.
     
    xarax, Nov 24, 2004
    #8
  9. Rogue Chameleon

    bilbo Guest

    Michael Borgwardt wrote:
    > Local variables live on the stack, thus they `*must* be known in

    advance.
    > Actually, in byte code, there is no such thing as variable scope

    either.

    Is this behavior actually required by a standard-conforming Java
    compiler or JVM, or is it just the way that the Sun JDK works? I know
    the asssembler output I've inspected from some C and C++ compilers does
    indeed decrement and increment the stack pointer when entering and
    leaving blocks, so block-scope variables really are implemented as
    block-scope. So I don't see why in principle a Java compiler couldn't
    couldn't do the same, unless the JVM doesn't support this, or the JLS
    forbids it.

    Even if the the JVM somehow doesn't support block-scope variables, a
    reasonable compiler could still generate extra code to set block-scope
    variables to null when the block exits, so that the object the
    block-scope variable referred to would be able to be GCed before the
    function exits. In fact I was surprised to find out that Sun's
    compiler doesn't do this. The first time I saw code like this:

    void someFunction() {
    if (someCondition) {
    SomeClass obj = new SomeClass();
    obj.doSomething();
    obj = null; // this surprised me
    }
    doOtherStuff();
    }

    (Sorry for the lack of indentation. The Google client strips all
    leading whitespace.)

    I thought it was silly to set obj to null at the end of the block,
    since it went out of scope there anyway. Later I learned that at least
    with Sun's JDK, the object created inside the "if" block actually can't
    be collected until the function exits, which could be a problem if
    SomeClass uses a lot of memory, and doOtherStuff() is a long running
    bit of code as well. It just seems wrong to have to do this kind of
    manual memory management in a GCed language, when the compiler easily
    has enough info to do the work for me.
     
    bilbo, Nov 24, 2004
    #9
  10. bilbo wrote:

    > Michael Borgwardt wrote:
    >
    >>Local variables live on the stack, thus they `*must* be known in

    >
    > advance.
    >
    >>Actually, in byte code, there is no such thing as variable scope

    >
    > either.
    >
    > Is this behavior actually required by a standard-conforming Java
    > compiler or JVM, or is it just the way that the Sun JDK works? I know


    It is a true statement about the characteristics of the bytecode
    language, which is independant of the Java language or any particular
    implementation of Java tools.

    > the asssembler output I've inspected from some C and C++ compilers does
    > indeed decrement and increment the stack pointer when entering and
    > leaving blocks, so block-scope variables really are implemented as
    > block-scope.


    That is both implementation-specific and irrelevant.

    > So I don't see why in principle a Java compiler couldn't
    > couldn't do the same, unless the JVM doesn't support this, or the JLS
    > forbids it.


    The JLS has nothing to say about it, as it is concerned with Java, not
    bytecode. A JVM could perhaps support such a thing as an extension, but
    classes that made use of such an extension would not be Java-compliant.
    For that you might as well just compile to native code -- you would
    already have given up most of the advantages of running in a VM anyway.

    > Even if the the JVM somehow doesn't support block-scope variables, a
    > reasonable compiler could still generate extra code to set block-scope
    > variables to null when the block exits, so that the object the
    > block-scope variable referred to would be able to be GCed before the
    > function exits.


    I don't accept that as a valid criterion for a compiler being
    "reasonable". Some would even argue (and have) that a compiler that did
    as you say would not be Java compliant. I would not personally go so
    far; I think such a compiler could be compliant, but I don't see the
    point of demanding one. You can expect a modern JIT-enabled JVM to
    compile the corresponding bytecode to native code at runtime if there is
    any significant advantage to doing so (and maybe even if there isn't),
    and to apply a fairly good suite of optimizations in the process. Such
    optimizations can include detecting when the current values of reference
    variables are no longer accessed along any potential forward code path,
    and taking appropriate action to avoid unnecessarily long-lived objects.
    Note that that is a more general optimization than automatically
    nullifying reference variables when they go out of (Java) scope.

    [...]

    > bit of code as well. It just seems wrong to have to do this kind of
    > manual memory management in a GCed language, when the compiler easily
    > has enough info to do the work for me.


    You don't have to do it. In most cases it won't make a difference
    anyway. In those cases where it might make a difference, the JIT has a
    chance to take care of you. If you actually experience difficulties
    with object packratting then a good profiler will help you figure out
    those places, if any, where explicitly nullifying reference variables
    may help.


    John Bollinger
     
    John C. Bollinger, Nov 24, 2004
    #10
  11. Rogue Chameleon

    Chris Uppal Guest

    xarax wrote:

    > > Not /quite/ identical, there's a good chance that the compiler will
    > > generate explicit bytecode for the assignment in:
    > >
    > > Object o = null;
    > >
    > > IIRC, the java 1.4.x series compilers did so (I haven't yet looked at
    > > the output from the 1.5.0 compiler in cases like this). Of course,
    > > there's then the JITer to consider...

    >
    > Actually, earlier compilers did NOT generate the
    > assignment, because the compiler noticed that the
    > initial value was the same as the default value.


    But by "earlier compilers" you mean 1.3 series or earlier ? I remember
    noticing the described behaviour in 1.4 series. Not that it matters -- this is
    nitpicking about nitpicking about nitpicking ;-)


    > Also, JIT'd code is supposedly debuggable now, so
    > an explicit assignment of a default value should
    > not get optimized away by the JIT.


    It's probably worth clarifying this a little -- it could be misinterpreted. As
    I understand it, the JITer is still allowed to remove the assignment to null
    (and for all I know that's what it does), it's just that it's required to /put
    it back/ if you place a breakpoint on it. (Chances are it'll put it back if
    you place a breakpoint anywhere in that method -- but that's an implementation
    detail and I'm /very/ sketchy on the details).

    -- chris
     
    Chris Uppal, Nov 25, 2004
    #11
  12. Chris Uppal wrote:
    > xarax wrote:
    >
    >>Also, JIT'd code is supposedly debuggable now, so
    >>an explicit assignment of a default value should
    >>not get optimized away by the JIT.

    >
    >
    > It's probably worth clarifying this a little -- it could be misinterpreted. As
    > I understand it, the JITer is still allowed to remove the assignment to null
    > (and for all I know that's what it does), it's just that it's required to /put
    > it back/ if you place a breakpoint on it. (Chances are it'll put it back if
    > you place a breakpoint anywhere in that method -- but that's an implementation
    > detail and I'm /very/ sketchy on the details).


    I created a little test class, and ran it through a little JVMTI agent
    that dumps the JIT-generated native code, and I can confirm that at
    least on the client 1.5.0 JVM on x86 linux, the explicit assignment was
    not removed in the JIT-ed code. That was the only difference between the
    compiled code of the two different approaches.

    The server VM on the same JVM did generate equivalent code for both
    approaches. I suspect the client VM does not do any dead code elimination.

    --
    Daniel Sjöblom
    Remove _NOSPAM to reply by mail
     
    =?ISO-8859-1?Q?Daniel_Sj=F6blom?=, Nov 25, 2004
    #12
  13. On Wed, 24 Nov 2004 11:47:22 -0500, Dave Stallard wrote:
    >
    >for (Iterator i=c.iterator();i.hasNext();)
    > Object o = i.next(); // You don't need the coercion for Object
    >
    >Of course, in the new Java you should be able to write something like:
    >
    >foreach (Object : c)
    >


    It's not the same, and the first (for (Iterator i) is even incorrect: it
    will fail when c is empty. You should always use Iterator it=..;while
    (it...) or the new (and much indeed much better) construct for (... :..)
    except when you're very sure the collection can never be empty.

    --
    Gerbrand van Dieijen
     
    Gerbrand van Dieijen, Nov 26, 2004
    #13
  14. Iterator - 'for' or 'while' (was: Which is better... performance-and memory-wise?)

    /Gerbrand van Dieijen/:
    > On Wed, 24 Nov 2004 11:47:22 -0500, Dave Stallard wrote:
    >
    >> for (Iterator i=c.iterator();i.hasNext();)
    >> Object o = i.next(); // You don't need the coercion for Object
    >>
    >> Of course, in the new Java you should be able to write something like:
    >>
    >> foreach (Object : c)

    >
    > It's not the same, and the first (for (Iterator i) is even incorrect: it
    > will fail when c is empty.


    I fail to see how it would fail if the iterator "is empty"?

    > You should always use Iterator it=..;while
    > (it...) or the new (and much indeed much better) construct for (... :..)
    > except when you're very sure the collection can never be empty.


    The 'for' construct has the same effect as with the previous example
    - it just hides the Iterator's visibility making it the preferred
    for me.

    --
    Stanimir
     
    Stanimir Stamenkov, Nov 26, 2004
    #14
  15. Rogue Chameleon

    Chris Uppal Guest

    Daniel Sjöblom wrote:

    > I created a little test class, and ran it through a little JVMTI agent
    > that dumps the JIT-generated native code, and I can confirm that at
    > least on the client 1.5.0 JVM on x86 linux, the explicit assignment was
    > not removed in the JIT-ed code. That was the only difference between the
    > compiled code of the two different approaches.
    >
    > The server VM on the same JVM did generate equivalent code for both
    > approaches. I suspect the client VM does not do any dead code elimination.


    Interesting. Thank you.

    -- chris
     
    Chris Uppal, Nov 26, 2004
    #15
  16. Rogue Chameleon

    Grant Wagner Guest

    Gerbrand van Dieijen wrote:

    > On Wed, 24 Nov 2004 11:47:22 -0500, Dave Stallard wrote:
    > >
    > >for (Iterator i=c.iterator();i.hasNext();)
    > > Object o = i.next(); // You don't need the coercion for Object
    > >
    > >Of course, in the new Java you should be able to write something like:
    > >
    > >foreach (Object : c)
    > >

    >
    > It's not the same, and the first (for (Iterator i) is even incorrect: it
    > will fail when c is empty.


    import java.util.*;

    public class IteratorTest {
    public static void main(String[] s) {

    ArrayList<String> c = new ArrayList<String>();

    // c.add("Test");

    System.out.println(
    "The ArrayList is " +
    (c.isEmpty() ? "" : "not ") +
    "empty"
    );

    for (Iterator i = c.iterator(); i.hasNext();) {
    Object o = i.next();
    System.out.println(o);
    }

    // no errors or exceptions, even when c 'isEmpty()'
    }
    }

    --
    Grant Wagner <>
     
    Grant Wagner, Nov 26, 2004
    #16
  17. On Fri, 26 Nov 2004 16:22:24 GMT, Grant Wagner wrote:
    > for (Iterator i = c.iterator(); i.hasNext();) {
    > Object o = i.next();
    > System.out.println(o);
    > }
    >


    Arg, you're right. I'm very ashamed I didn't thought about that, or
    figured it out before :-(
    --
    Gerbrand van Dieijen
     
    Gerbrand van Dieijen, Nov 26, 2004
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fred
    Replies:
    12
    Views:
    1,725
    Sandeep
    Oct 31, 2003
  2. Enrique Cruiz

    Row-wise vs. column-wise image processing

    Enrique Cruiz, Jan 25, 2007, in forum: C Programming
    Replies:
    10
    Views:
    727
    christian.bau
    Jan 26, 2007
  3. Enrique Cruiz
    Replies:
    5
    Views:
    428
    Jim Langston
    Jan 25, 2007
  4. Showjumper

    Performance wise whats better?

    Showjumper, Mar 3, 2005, in forum: ASP .Net Building Controls
    Replies:
    4
    Views:
    128
  5. Joey Martin
    Replies:
    28
    Views:
    276
    Bob Barrows [MVP]
    Jun 25, 2008
Loading...

Share This Page