Default Constructors
If there is no constructor defined inside a class, when creating the instance it makes calls to 2 constructors :
1. A constructor automatically generated by compiler.
2. It internally invokes constructor of Object class (which simply has an empty body)
Constructor calls matter because of method call overhead.
1. A constructor automatically generated by compiler.
2. It internally invokes constructor of Object class (which simply has an empty body)
Constructor calls matter because of method call overhead.
Constructor Hierarchies
When creating the instance it calls a chain of constructors, until the one in Object class.
At some point the expense can mount up using Method Inlining.
Class and Instance Initialization
When creating an instance, initialization of instance variables (variables unique to each instance) must be done.
Class variables (which are static and shared across instances) need only be initialized once, conceptually at program invocation time.
Class variables (which are static and shared across instances) need only be initialized once, conceptually at program invocation time.
The difference between these types of initialization is quite important,
Datamonths[] = {
newData(1, "January"), new Data(2, "February"),
newData(3, "March"), new Data(4, "April"),
newData(5, "May"), new Data(6, "June")
newData(3, "March"), new Data(4, "April"),
newData(5, "May"), new Data(6, "June")
};
Here, declaring this member as static give you huge difference.
Method Inlining
Most effective way to deal with method call overhead is method inlining, either by a compiler doing it automatically, or doing it yourself manually.
Inlining is done by expanding the inlined method’s code in the code that calls the method.
Inlining is done by expanding the inlined method’s code in the code that calls the method.
It makes code execution nearly twice as fast.
JIT compiler will by default inline some important methods.
Final Methods / Class
One way you can help a compiler with inlining is to declare final methods and final class (where all method would be implicitly final)
Synchronized methods
Synchronized methods are slower than non-synchronized ones, because of the overhead associated with obtaining a lock on the method’s object.
The synchronized call takes about twice as long as the non-synchronized one.
Collection classes like ArrayList are not themselves thread-safe, but they have mechanisms whereby you can add a thread-safe wrapper on top of a collection class instance.
This approach is useful in designing your own classes.
This approach is useful in designing your own classes.
Inner classes
A private method of a class A can be used by a class B, if B is the inner class inside A.
Because the JVM has restrictions on calling private members from outside of their class, a special access method is generated by the compiler and added internally to the meth_inner class. This method has a name access$0(),and it in turns calls f().
Because the JVM has restrictions on calling private members from outside of their class, a special access method is generated by the compiler and added internally to the meth_inner class. This method has a name access$0(),and it in turns calls f().
You can avoid this overhead by avoiding use of private members in a class, assuming the class has inner classes that use those members.
Strings are Immutable
Strings are immutable - Never change after creation , but a reference to the string may change.
The two strings to be concatenated are copied to a temporary string buffer, then copied back.
Such copying is quite expensive.
So, Use StringBuffer objects explicitly if you’re building up a string.
String concatenation operators like + and += are fine for casual use, but quite expensive otherwise.
String concatenation operators like + and += are fine for casual use, but quite expensive otherwise.
Example : A program takes around 2400 units of time to run using the + operator, and about 60 units of time using StringBuffer.append(), a difference of 40-1.
Accumulating Strings using char[ ] Arrays
If size of output string is already known, create an output char[] array, add characters to it, and then convert the result to a string.
Java characters are encoded as 1, 2 or 3 bytes in the UTF-8 scheme, so when a stream of bytes is converted back to characters, it is guaranteed that the number of characters will never be more than the number of bytes.
This particular technique trades some extra memory usage for improved speed.
Using == and String.equals() to compare strings
== operator simply compares the references themselves for equality
Usage : if (s1 == s2 || s1.equals(s2))
== is much less expensive to perform than equals().
Interning Strings
String.intern() is used to create an internal pool of unique strings.
str= str.intern();
adds the stringto the internal pool if not already there, and returns a reference to the interned string.
Interned strings can be compared with each other using ==, which is much cheaper than using equals() to do the comparison.
String literals are always interned.
Obtaining the Length of a String
If you call length() in a tight loop, there can be a performance hit.
for(int i = 0; i < s.length(); i++)
Example: using length() takes 1733 units of time, while if the string length is precomputed and stored in a local variable, the total time is 1282 units.
It’s more costly to call method than it is to precompute the length.
Using toCharArray()
charAt() is a String method similar to length(), which can be expensive if called for every character in a long string.
An alternative to this method is use of toCharArray(), which returns a copy of the string in a char[] array.
Exporting the characters in a string to a char[] array eliminates the method call overhead of charAt(), at the expense of committing extra memory to the char[ ] copy that is made.
Calling a method length() has the expense of method call overhead, and obtaining the length of an array via the special length field simply retrieves the array length from a run time descriptor.
Converting Strings to Numbers
Creating a Double from a string takes about 15 times as long as from a number.
Often you have no choice to do conversion of strings to numbers, but it’s worth keeping in mind the expense of this operation
Buffering
Most important idea in improving I/O performance is buffering, doing input and output in large chunks instead of a byte or character at a time.
Example
fis.read() // single byte read
fis.read(buf) // read bytes using byte[] buf
Buffering approach avoids method call overhead, and because each call to read(), whether for a single byte or a large chunk of bytes, results in a call to the underlying operating system (the read() methods are declared native in java.io.FileInputStream).
BufferedReader
One I/O layercan be added on top of another, to provide additional functionality.
Example
1. Reads all the characters from a file using a FileReader class,
2. Reads all characters, but this time with a BufferedReader layered on top of the FileReader.
The second approach runs about four times as fastas the first, because there’s less overhead incurred per character.
BufferedReader reads characters in chunks several thousand long, and then parcels them out one at a time.
read() method found in BufferedReader simply hands back characters from a buffer, which is quite efficient.
Formatting
1. Use string concatenation :
s = "The square of " + i + " is " + (i * i);
2. java.text.MessageFormat, with a precompiled format string :
MessageFormatf = new MessageFormat("The square of {0,number,#} is {1,number,#}");
Strings = f.format(new Object[]{new Integer(i), new Integer(i*i)});
3. Similar to the second, but uses an on-the-fly message format that has not been precompiled
Stringf = "The square of {0,number,#} is {1,number,#}";
Strings = MessageFormat.format(f, new Object[]{new Integer(i), new Integer(i*i)});
Formatting costs :
1. 1953
2. 12027
3. 41409
MessageFormat is quite an important tool if you’re trying to internationalize your applications.
But it’s worth understanding the relative costs of different formatting approaches.
Obtaining File Information
File.length() itself doesn’t know the length, and so it calls upon the underlying operating systemto retrieve the length, which might, for example, be obtained via a stat() system call.
Such calls are relatively expensive.
(Also applies for operations like file length, whether a file is a directory or a plain file,attributes such as read/write permissions, and so on)
If you’ve already obtained a file’s length, don’t call for it again a few lines down in your program, unless you have reason to believe the length has changed in the meantime.
System.arraycopy() method
System.arraycopy() is a method that supports efficient copying from one array to another.
System.arraycopy() improves performance, over alternative approaches for copying arrays.
Cost :
loop = 381
System.arraycopy = 40
Object.clone = 150
Note that Object.clone() does a shallow copy, as does System.arraycopy(), so if the array elements are object references, the references are copied, and copy is made of the referenced objects.
Vector vs. ArrayList
Vector’s methods are synchronized, ArrayList’s are not. This means that Vector is threadsafe, at some extra cost.
When Vector needs to grow its internal data structure to hold more elements, the size of the structure is doubled, whereas for ArrayList, the size is increased by 50%.So ArrayList is more conservative in its use of space.
Setting Initial Array Capacity
Collection classes like ArrayList periodically must grow their internal data structures to accommodate new elements.
If you have avery large array, and you know in advance that it’s going to be large, then you can speed things up a bit by calling ensureCapacity() toset the size of the array.
Calling ensureCapacity() means that ArrayList will not have to keep growing the internal structures as list elements are added.
If you define capacity, it runs about 15% faster than if you don’t define it.
if you define capacity, when you don’t really need it, you may end up wasting a lot of space.
ArrayList vs. LinkedList
ArrayList is implemented using an internal array of Object[ ], while a LinkedList uses a series of internal records linked together.
Inserting elements at the beginning of an ArrayList requires that all existing elements be pushed down.
This is a very expensive operation.
But inserting at the beginning of LinkedList is cheap, because the elements of the structure are connected with each other via links, and it’s easy to create a new element and link it in withthe current element at the head of the list.
To randomly access the elements of a list, that’s cheap to do with an ArrayList, but expensive with a linked list (because you must iterate over the elements of the list to find the right one)
ArrayList offers superior performance if you’re adding elements to the end of the list, then looking them up randomly, whereas LinkedList is a better choice if you’re adding and deleting elements at the front or middle of the list, and accessing elements mostly in sequential order via iterators that step through the list elements.
Programming in Terms of Interfaces
Listlist = new ArrayList();
voidf(List list) {...}
You can use List everywhere in your programming, and you don’t have to worry too much about whether list is really an ArrayList or a LinkedList (it might actually be a custom-designed collection class, in fact). In other words, you program in terms of functionality offered by interface types, and you can switch the actual implementation easily at some later point, for reasons of efficiency.
Wrappers
Wrapper classes have some overhead, both in time and space costs.
It’s less efficient to extract a value from a wrapper instance than it is to use the value directly. And there are costs in creating all those wrapper instances, both time costs in calling new and constructors, and space costs with the overhead that comes with class instances.
(a very rough estimate might be that an instance of a class takes 15 bytes, in addition to the size of the actual instance variables)
Garbage Collection
If you have a reference to a large, no-longer-used object, and the reference is one that will stay in scope for some time to come, then you might want to clear the reference explicitly, by setting it to null.
Sparse / zagged Arrays
Object pages[][] = new Object[2][];
pages[0] = new Pages[3];
pages[1]= new Pages[15];
Use sparse / zagged array for storing array more efficiently.
No comments:
Post a Comment
Note: only a member of this blog may post a comment.