Is repeatedly instantiating an anonymous class wasteful?

后端 未结 3 727
借酒劲吻你
借酒劲吻你 2021-02-14 02:32

I had a remark about a piece of code in the style of:

Iterable upperCaseNames = Iterables.transform(
    lowerCaseNames, new Function

        
相关标签:
3条回答
  • 2021-02-14 02:45

    Found this thread: Java anonymous class efficiency implications , you may find it interesting

    Did some micro-benchmarking. The micro-benchmark was a comparison between: instantiating an (static inner) class per loop iteration, instantiating a (static inner) class once and using it in the loop, and the two similar ones but with anonymous classes. For the micro benchmarking the compiler seemed to extract the anonymous class out of loops and as predicted, promoted the anonymous class to an inner class of the caller. This meant all four methods were indistinguishable in speed. I also compared it to an outside class and again, same speed. The one with anonymous classes probably took ~128 bits of space more

    You can check out my micro-benchmark at http://jdmaguire.ca/Code/Comparing.java & http://jdmaguire.ca/Code/OutsideComp.java. I ran this on various values for wordLen, sortTimes, and listLen. As well, the JVM is slow to warm-up so I shuffled the method calls around. Please don't judge me for the awful non-commented code. I program better than that in RL. And Microbenching marking is almost as evil and useless as premature optimization.

    0 讨论(0)
  • 2021-02-14 02:52

    Short answer: No - don't worry.

    Long answer: it depends how frequently you're instantiating it. If in a frequently-called tight loop, maybe - though note that when the function is applied it calls String.toUpperCase() once for every item in an Iterable - each call presumably creates a new String, which will create far more GC churn.

    "Premature optimization is the root of all evil" - Knuth

    0 讨论(0)
  • 2021-02-14 03:03

    Fun fact about Sun/Oracle JVM optimizations, if you instantiate an object that isn't passed outside of the thread, the JVM will create the object on the stack instead of the heap.

    Usually, stack allocation is associated with languages that expose the memory model, like C++. You don't have to delete stack variables in C++ because they're automatically deallocated when the scope is exited. This is contrary to heap allocation, which requires you to delete the pointer when you're done with it.

    In the Sun/Oracle JVM, the bytecode is analyzed to decide if an object can "escape" the thread. There are three levels of escape:

    1. No escape - the object is only used within the method/scope it is created, and the object can't be accessed outside the thread.
    2. Local/Arg escape - the object is returned by the method that creates it or passed to a method that it calls, but none of the methods in the current stack trace will put that object somewhere that it can be accessed outside of the thread.
    3. Global escape - the object is put somewhere that it can be accessed in another thread.

    This basically is analogous to the questions, 1) do I pass/return it, and 2) do I associate it with something attached to a GC root? In your particular case, the anonymous object will be tagged as "no local escape" and will be allocated to the stack, then cleaned up by simply popping the stack on each iteration of the for loop, so cleaning it up will be super-fast. Sorry, I wasn't paying much attention when I wrote up my answer. It's actually local escape, which only means that any locks (read: use of synchronized) on the object will be optimized away. (Why synchronize on something that won't ever be used in another thread?) This is different from "no escape", which will do allocation on the stack. It's important to note that this "allocation" isn't the same as heap allocation. What it really does is allocates space on the stack for all the variables inside the non-escaping object. If you have 3 fields, int, String, and MyObject inside the no-escape object, then three stack variables will be allocated: an int, a String reference, and a MyObject reference. The object allocation is then optimized away and constructors/methods will run using the local stack variables instead of heap variables.

    That being said, it sounds like premature optimization to me. Unless the code is later proven to be slow and is causing performance problems, you shouldn't do anything to reduce its readability. To me, this code is pretty readable, I'd leave it alone. This is totally subjective, of course, but "performance" is not a good reason to change code unless it has something to do with its algorithmic running time. Usually, premature optimization is an indicator of an intermediate-level coder. "Experts" (if there is such a thing) just write code that's easier to maintain.

    0 讨论(0)
提交回复
热议问题