Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (527)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (593)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Beware of Enum.values()!  (Read 4032 times)
0 Members and 1 Guest are viewing this topic.
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Posted 2013-03-10 20:53:12 »

Although rarely used, Enum.values() is a function that returns an array holding all the possible values of the specified Enum. It generates a new array every time it's called! Since there's no way to force the immutability of the array, I guess that was their only way of doing this.

I just eliminated 200+MB/s of garbage by writing my own cached values() function which returns a precomputed static array of the values in the enum.

1  
2  
3  
4  
   private static EnumName[] values = values();
   public static EnumName[] valuesCached(){
      return values;
   }


EDIT: Modified the code example to look more sane with syntax highlighting.

Myomyomyo.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 834
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2013-03-10 21:18:00 »

Same for any critical method that returns supposedly immutable JVM state.

Class.getName() -> new String instance
Class.getMethods() -> new array of new Method instances

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #2 - Posted 2013-03-10 21:20:07 »

Also, varargs. Sad

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline concerto49

Junior Devvie





« Reply #3 - Posted 2013-03-10 22:44:33 »

Also, varargs. Sad

What does varargs have to do with immutable arrays?

High performance, fast network, affordable price VPS - Cloud Shards
Available in Texas, New York & Los Angeles
Need a VPS Upgrade?
Offline nsigma
« Reply #4 - Posted 2013-03-10 23:32:52 »

Class.getName() -> new String instance

Why the hell would getName() have to create new Strings?


While I'm not sure what Nate means exactly, one thing that's annoying with varargs is that they accept arrays, which means if you need to ensure it's private you need to clone the array you get, despite the fact that 99% of the time it's pointless.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 834
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #5 - Posted 2013-03-10 23:41:08 »

Class.getName() -> new String instance

Why the hell would getName() have to create new Strings?

Because using reflection, you can alter the char[] that is backing the String, messing up JVM & app logic.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline nsigma
« Reply #6 - Posted 2013-03-11 00:02:05 »

@Riven - ah, yes. A pointless thing to guard against in (most) user code, but makes sense for the JVM.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline davedes
« Reply #7 - Posted 2013-03-11 00:40:25 »

Nice tip. I really like working with Enums, so I tend to use this commonly.

Regarding varargs; I think the problem NateS is talking about is when you use it like this:

1  
2  
3  
public void draw(Texture ... textures) {
    ...
}


As I understand it, a new array is created whenever you call that method, regardless of parameter count:
1  
2  
3  
draw(); // -> new array length 0
draw(tex); // -> new array length 1
draw(tex, tex2); //new array length 2


Or maybe he is talking about something else... Smiley

Offline ReBirth
« Reply #8 - Posted 2013-03-11 01:22:13 »

Wow I use values() a lot! Shocked

About varargs, passing the array reference solves don't it?
1  
public void test(T[] t);

Offline ra4king

JGO Kernel


Medals: 355
Projects: 3
Exp: 5 years


I'm the King!


« Reply #9 - Posted 2013-03-11 04:39:47 »

Holy shitballs thank you, I just changed fixed my code to cache the values() array Stare

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline nsigma
« Reply #10 - Posted 2013-03-11 09:19:33 »

About varargs, passing the array reference solves don't it?
1  
public void test(T[] t);


I know why that's allowed, but I wish it wasn't (see my earlier comment).

The varargs array is a prime candidate for removal via escape analysis.  This may not be the panacea you're looking for.  Wink

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline nsigma
« Reply #11 - Posted 2013-03-11 10:53:19 »

@Riven - ah, yes. A pointless thing to guard against in (most) user code, but makes sense for the JVM.

Follow up - except according to the code here (http://hg.openjdk.java.net/jdk7u/jdk7u-gate/jdk/file/965f6e358f61/src/share/classes/java/lang/Class.java) it actually doesn't!   persecutioncomplex

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline sproingie

JGO Kernel


Medals: 202



« Reply #12 - Posted 2013-03-11 15:53:59 »

The array returned by Enum.values() is not going to change at runtime.  You don't so much need to cache it automatically as simply give it a scope that's appropriate for where you're using it.  Maybe that's global, so the static cache location is appropriate then, but don't just cargo-cult valuesCached() onto your enum classes without first seeing if you can just hoist the values() array out of your loop instead.
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #13 - Posted 2013-03-11 16:52:41 »

The array returned by Enum.values() is not going to change at runtime.  You don't so much need to cache it automatically as simply give it a scope that's appropriate for where you're using it.  Maybe that's global, so the static cache location is appropriate then, but don't just cargo-cult valuesCached() onto your enum classes without first seeing if you can just hoist the values() array out of your loop instead.
In my test I couldn't get it out of the loop. I'm looping over the 6 different sides of a voxel and transform them based on a rotation (all precomputed so it simply follows a few references to do the calculations), so I needed to loop over the sides. I don't know if it's a 100% valid use of enums or values() in the first place, but I did notice that it produced a shitload of garbage when I (re)generated the geometry of chunks which happens for the first few seconds when the game starts.

I just decided to post this because the fix is so ridiculously simple as long as you promise not to change the content of the array. People seem to have had the same problem with other things that return arrays too, so I just thought it was posting since someone might be calling those functions a lot like me. ^^ values() is rarely used in the first place, so of course I wouldn't just throw in valuesCached() into every enum I create. In fact I'm still using values() during load time since I only bothered to change my code to use valuesCached() when it actually mattered.

Myomyomyo.
Offline sproingie

JGO Kernel


Medals: 202



« Reply #14 - Posted 2013-03-11 17:02:23 »

Java has to make a defensive copy of the array, since it lacks the concept of an immutable array type.  It could theoretically hoist it out of the loop, but the data flow analyzer doesn't take heroic measures (the general problem of deciding a value's lifetime is undecideable) so it's going to leave the array creation in the loop most if not all of the time.

Sometimes the best use case is to cache the values right on the enum type, sure.  I'm just warning against blindly applying this everywhere (thus the "cargo-cult" reference) when simply assigning the array locally once outside the loop might sometimes be more appropriate.
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #15 - Posted 2013-03-11 17:19:43 »

Java has to make a defensive copy of the array, since it lacks the concept of an immutable array type.  It could theoretically hoist it out of the loop, but the data flow analyzer doesn't take heroic measures (the general problem of deciding a value's lifetime is undecideable) so it's going to leave the array creation in the loop most if not all of the time.
I'm... pretty sure I just said that the original post... ^^'

Myomyomyo.
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #16 - Posted 2013-03-11 22:46:36 »

Regarding varargs; I think the problem NateS is talking about is when you use it like this:
Yep, using varargs allocates anew array, which is annoying.

Offline noblemaster

« JGO Spiffy Duke »


Medals: 20
Projects: 10


Age of Conquest makes your day!


« Reply #17 - Posted 2013-03-12 07:55:29 »

Also, addAll(...) in ArrayList creates a new array each time before adding the elements!

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.addAll%28java.util.Collection%29

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 834
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2013-03-12 08:42:26 »

Similarily, Collections.sort(...) also creates a Object[] to do the actual sorting.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline ReBirth
« Reply #19 - Posted 2013-03-12 12:08:51 »

Also, addAll(...) in ArrayList creates a new array each time before adding the elements!
Similarily, Collections.sort(...) also creates a Object[] to do the actual sorting.
Life is so hard...

Offline Catharsis

JGO Coder


Medals: 16
Projects: 1
Exp: 18 years


TyphonRT rocks!


« Reply #20 - Posted 2013-03-12 18:11:29 »

Since we're expanding on various oddities.. With J2SE Enum hashCode() returns the identity hash code on Android hashCode() returns the ordinal + hash code of the String name of the enum. Doh! If you try and mix a lot of Enum with other objects returning the identity hash code on Android collisions potentially occur. Also if you have two Enum classes with a duplicate name in the same position the hash codes collide. Doh!

On Android:
1  
2  
3  
4  
    @Override
    public final int hashCode() {
        return ordinal + (name == null ? 0 : name.hashCode());
    }

Please support my Kickstarter for next-gen video apps for Android:
http://kck.st/1xA3R61

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline Dejay

Senior Newbie


Medals: 3



« Reply #21 - Posted 2013-03-14 04:45:59 »

I was a curious and made a few tests because I thought escape analysis would simply take care of this as long as you don't keep a reference to the Enum.values(). But it doesn't. It seems escape analysis only works for primitive arrays as a VarArg parameter.

VarArgs are ok IF they are primitive and smaller than 64 elements, then they are simply allocated on the stack. Here is a link to a test program, with escape analysis that specific test is a 110 times faster! But it doesn't seem to work for object arrays :/

Defensive copies of objects returned or temp objects work rather well though.

The lack of documentation and JIT compiler makes it really hard to test this stuff.
Online princec

« JGO Spiffy Duke »


Medals: 425
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #22 - Posted 2013-03-14 10:49:00 »

It could be argued that if you've got a varargs argument in a performance critical section of code you're maybe not writing performance aware code in the first place of course.

Cas Smiley

Offline relminator
« Reply #23 - Posted 2013-03-14 11:20:47 »

Thanks!!! I was about to use Enum.values() for my singleton explosion class.

Offline nsigma
« Reply #24 - Posted 2013-03-14 12:21:26 »

VarArgs are ok IF they are primitive and smaller than 64 elements, then they are simply allocated on the stack. Here is a link to a test program, with escape analysis that specific test is a 110 times faster! But it doesn't seem to work for object arrays :/

I'd meant to link to that article earlier and forgot.  However, where are you getting the "doesn't seem to work for object arrays" from?  The linked article doesn't seem to imply that, so wondered about the test.  I would have thought the JIT compiler could easily inline the object references to remove the array, even if not inlining fields from the objects themselves!?

It could be argued that if you've got a varargs argument in a performance critical section of code you're maybe not writing performance aware code in the first place of course.

hmm ... yes and no ... potentially.  I read another article recently (and can't remember the damn link) which suggested varargs could be faster than passing in a cached array because escape analysis might remove the array access code too.

Have I added in enough "could"s, "suggested"s, "might"s and "pray to the magic fairy" in all that?  Grin

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Online princec

« JGO Spiffy Duke »


Medals: 425
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #25 - Posted 2013-03-14 15:40:03 »

I was more thinking along the lines of, if you're calling a fairly generic function that's meant to take arbitrary parameters, but you are in performance critical code and already know in advance what your parameters are... may as well optimise that properly.

Cas Smiley

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

PocketCrafter7 (12 views)
2014-11-28 16:25:35

PocketCrafter7 (7 views)
2014-11-28 16:25:09

PocketCrafter7 (8 views)
2014-11-28 16:24:29

toopeicgaming1999 (74 views)
2014-11-26 15:22:04

toopeicgaming1999 (63 views)
2014-11-26 15:20:36

toopeicgaming1999 (15 views)
2014-11-26 15:20:08

SHC (29 views)
2014-11-25 12:00:59

SHC (27 views)
2014-11-25 11:53:45

Norakomi (32 views)
2014-11-25 11:26:43

Gibbo3771 (28 views)
2014-11-24 19:59:16
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!