6 Replies - 413 Views - Last Post: 14 June 2017 - 07:17 AM

#1 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 5922
  • View blog
  • Posts: 20,246
  • Joined: 05-May 12

Does this really affect the young collection?

Posted 12 June 2017 - 10:45 AM

I'm on the learning curve for Java and I was reviewing some code written by a more experienced developer.

They wrote something like this:
ArrayList<string> allResults = getAllResults();
ArrayList<string> someResults = getSomeResults();

if (allResults != null) {
    for(int i = 0; i < allResults.size(); i++) {
        if (someResults != null) {
            for(int j = 0; j < someResults.size(); j++) {
                if (allResults.get(i) != null && allResults.get(i).contains(someResults.get(j))) {
                    doSomething(allResults.get(i));
                }
            }
        }
    }
}



I had commented that if (someResults != null) should be moved out of the loop, and that allResults.get(i) should probably be grabbed in a variable. Something like:
ArrayList<string> allResults = getAllResults();
ArrayList<string> someResults = getSomeResults();

if (allResults != null && someResults != null) {
    for(int i = 0; i < allResults.size(); i++) {
        string haystack = allResults.get(i);

        for(int j = 0; j < someResults.size(); j++) {
            if (haystack != null && haystack.contains(someResults.get(j))) {
                doSomething(haystack);
            }
        }
    }
}



Spoiler


The change for the former was accepted, but I got push back on the latter change about declaring the haystack variable. The reason given was that by declaring that variable and assigning a value to it, extra memory would be used up in the young collection and thereby putting more memory pressure on our systems. My initial response was that I expected that I expected haystack to be on the stack and not involve the young collection, but I don't really have enough Java experience to confirm that expectation.

So Java experts: Does that argument that we'll be putting more memory pressure by declaring local variables to hold water? Would it make any difference if it were written as:
ArrayList<string> allResults = getAllResults();
ArrayList<string> someResults = getSomeResults();

if (allResults != null && someResults != null) {
    for(int i = 0; i < allResults.size(); i++) {
        string haystack = allResults.get(i);

        for(int j = 0; j < someResults.size(); j++) {
            if (haystack != null && haystack.contains(someResults.get(j))) {
                doSomething(haystack);
            }
        }
        haystack = null;
    }
}



Is This A Good Question/Topic? 1
  • +

Replies To: Does this really affect the young collection?

#2 modi123_1  Icon User is offline

  • Suitor #2
  • member icon



Reputation: 13553
  • View blog
  • Posts: 54,090
  • Joined: 12-June 08

Re: Does this really affect the young collection?

Posted 12 June 2017 - 01:28 PM

I am not familiar with the term "young collection". What is that? Something to do with the scope for a given declared collection?

As for preference I would swing the first one. There wasn't a need to dump the data into another variable when the reference to the collection is just fine. I wouldn't think an "alias" as the variable would be needed.
Was This Post Helpful? 1
  • +
  • -

#3 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 5922
  • View blog
  • Posts: 20,246
  • Joined: 05-May 12

Re: Does this really affect the young collection?

Posted 12 June 2017 - 01:53 PM

By "young collection", he was referring to the first round of garbage collection.

This shows my Java naivete, but I'll ask anyway: Doesn't each call to get() also end up re-running the full bounds checking? Or is the Java compiler smart enough to not to have to call get() multiple times? So if the container were not an ArrayList<string> but something like a linked list, tree, or a hash table that has a relatively expensive hash computation, is the preference still to do repeated calls through the container's get() method?
Was This Post Helpful? 0
  • +
  • -

#4 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Does this really affect the young collection?

Posted 13 June 2017 - 10:53 AM

View PostSkydiver, on 12 June 2017 - 10:53 PM, said:

Doesn't each call to get() also end up re-running the full bounds checking?


I'd expect that neither of the calls to get would lead to a bounds check - not after JITing anyway.

The JIT elides bounds checks on array accesses when it can prove that an access will always be in bounds. One common example of that is that for(int i=0; i<arr.length; i++) f(arr[i]); will cause no bound checks (after JITing) because the JIT can tell that the loop condition already implies the condition that the bounds check would be checking.

Now, you have an ArrayList, not an array, but I'm pretty sure that the calls to size() and get() will be inlined, so you'll end up with something very close to the above example. So I'd expect there to be no bounds checks.
Was This Post Helpful? 1
  • +
  • -

#5 xclite  Icon User is offline

  • I wrote you an code
  • member icon


Reputation: 1249
  • View blog
  • Posts: 4,042
  • Joined: 12-May 09

Re: Does this really affect the young collection?

Posted 13 June 2017 - 05:40 PM

From a readability standpoint, I find extracting "haystack" to be dramatically better. Not only is this less cognitive load, it also provides better debugging information when you're trying to track down things like NPE.

Further, anybody who counters a comment about organization on a code review with the generation that the object's garbage will live in is missing the forest for the trees. Trust in the JVM to deal with this, and prove it's a problem with benchmarks.
Was This Post Helpful? 1
  • +
  • -

#6 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 5922
  • View blog
  • Posts: 20,246
  • Joined: 05-May 12

Re: Does this really affect the young collection?

Posted 13 June 2017 - 06:16 PM

Is there even a garbage collection issue? Does the line string haystack = someResults.get(I); allocate a brand new string or set a reference to a string in the array list? If it's just a reference, my understanding is that only stack space will be used for haystack to hold a reference the the string. So no garbage collection involved at all with regards to haystack.
Was This Post Helpful? 0
  • +
  • -

#7 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Does this really affect the young collection?

Posted 14 June 2017 - 07:17 AM

View PostSkydiver, on 14 June 2017 - 03:16 AM, said:

Is there even a garbage collection issue?


At first I was thinking that your colleague may have been talking about haystack extending the life time of the referenced object since now the result of the method call is assigned to a variable instead of just being temporary. So it can't be collected until haystack is re-assigned. So if there were a collection between the moment where you needed the object and the moment where you re-assign haystack, it might be moved to the next generation instead of being collected right there.

But then I realized that the method you're calling is get(), which does not create a new object, but only returns a reference to an existing from the ArrayList. So the object returned by get won't be eligible for collection until the list goes out of scope regardless of your haystack variable.

So no, I can't see any way in which the existence of your haystack variable would affect GC.

Quote

Does the line string haystack = someResults.get(I); allocate a brand new string or set a reference to a string in the array list?


The latter.

Quote

If it's just a reference, my understanding is that only stack space will be used for haystack to hold a reference the the string. So no garbage collection involved at all with regards to haystack.


Right, variables only affect GC in the sense that an object won't be collected while a variable refers to it. Creating a variable won't create additional objects compared to a version where the object isn't stored in a variable.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1