Monday, March 9, 2015

Best Practices for Coding - Java

Hi all,

After a while without publish anything, due family growing and moving to other country once again, I'm back now publishing some tips for better code, maintainability and some that will help you keep your memory usage footprint low. Of course if the project has a not very optimal architecture will be  hard just with code keep low memory footprint, though good code always helps.
This one is long, I have read articles from Oracle, across the web and the Java Performance Book (Link for Amazon Book) that I recommend and it's a really good book for those that want to have better performance with Java.
In this post, nearly all tips and good practices are for code, I hope this helps those one looking for improve their code or trying to set a bar for the minimum acceptable code quality.


Things to avoid at all cost in code, this is a basic thing and it’s an issue in most projects.
As the very first thing I would like to say to the developer to do is don’t be lazy in create object, variables or any other reference names, don’t make economy, use names that explain for any person what that reference.variable name really means, don’t expect that others guess what you were thinking earlier, not even make the mistake to think that you will remember exactly what the short naming mean after a couple of months doing something else in the project, be clear and verbose in explain a declaration.
E.g.:
// Don’t
public class BfProcCustAss {…
Object custAssActTdy = getCustomer();
// Do
public class BackfileProccessForCustmerAssociated {…
Object customerAssociatedActiveToday = getCustomer();

Avoid duplicated strings in the code as it is bad for code maintenance and memory, producing fragmented memory.
// Don’t – here you have two objects without any variable or instance variable association
If (customerType.equals(“Active”)) {
                foo.callCustomer(“Active”);
….
}

// Do – here you have one String object and two references to it
private static final String ACTIVE = “Active”;
// or
private final String ACTIVE = “Active”;
….
If (customerType.equals(ACTIVE)) {
                foo.callCustomer(ACTIVE);
….
}

NO, magical numbers please!
Try avoid those numbers that make so much sense to you at the code conception time though after a while not even you will be able to understand what it means.
E.g.:
final List<Object> myDifferentObjectList = getHeterogeneousObjectList();
// Don’t
BeanOne beanOne = myDifferentObjectList.get(5);

// Do
// Declare it in your method as var or as instance variable in your class
Private static final int BEAN_ONE = 5;
// Then
BeanOne beanOne = myDifferentObjectList.get(BEAN_ONE);


Or
// Don’t
cs.setString(2, feedToLookUp);
cs.setString(3, feedType);
cs.registerOutParameter(4, OracleTypes.CURSOR); // What are you getting from here?
cs.registerOutParameter(5, OracleTypes.VARCHAR); // and here?

// Do
final int PI_FEED_LOOK_UP = 2;
final int PI_FEED_TYPE = 3;
final int PO_RC_FEED_LIST = 4;
final int PO_MESSAGE_GROUP_ID = 5;

cs.setString(PI_FEED_LOOK_UP, feedToLookUp);
cs.setString(PI_FEED_TYPE, feedType);
cs.registerOutParameter(PO_RC_FEED_LIST, OracleTypes.CURSOR);  // Easier no?
cs.registerOutParameter(PO_MESSAGE_GROUP_ID, OracleTypes.VARCHAR);

Those tips above should be used with any language, not been restricted to Java, it’s a minimum for provide some code insight to the next developer that will maintain the code made by you.


The tips bellow are good for C++ and Java, however a few will be Java only as C++ has a quite better set for work with Threads than Java does, even today with the new Fork and Join released in JDK 7.


Avoid or Minimize Synchronization
Many performance studies have shown a high performance cost in using synchronization in Java. Improper synchronization can also cause a deadlock, which can result in complete loss of service because the system usually has to be shut down and restarted. But performance overhead cost is not a sufficient reason to avoid synchronization completely. Failing to make sure your application is thread-safe in a multi-threaded environment can cause data corruption, which can be much worse than losing performance. The following are some practices that you can consider to minimize the overhead:
Synchronize Critical Sections Only
Do Not Use the Same Lock on Objects That Are Not Manipulated Together
Use Private Fields
Use a Thread Safe Wrapper
Use Immutable Objects
Know Which Java Objects Already Have Synchronization Built-in
Do Not Under-Synchronize


Synchronize Critical Sections Only
If only certain operations in the method must be synchronized, use a synchronized block with a mutex instead of synchronizing the entire method. For example:
private Object mutex = new Object();
    ...
    private void doSomething()
    {
     // perform tasks that do not require synchronicity
        ...
        synchronized (mutex)
            {
            ...
            }
        ...
    }


Do Not Use the Same Lock on Objects That Are Not Manipulated Together
Every Java object has a single lock associated with it. If unrelated operations within the class are forced to share the same lock, then they have to wait for the lock and must be executed one at a time. In this case, define a different mutex for each unrelated operation that requires synchronization.
Also, do not use the same lock to restrict access to objects that will never be shared by multiple threads. For example, using Hashtables to store objects that will never be accessed concurrently causes unnecessary synchronization overhead:
public class myClass
{
    private static myObject1 myObj1;
    private static mutex1 = new Object();
    private static myObject2 myObj2;
    private static mutex2 = new Object();
    ...
    public static void updateObject1()
        {
            synchronized(mutex1)
            {
            // update myObj1 ...
            }
        }
    public static void updateObject2()
    {
                                synchronized(mutex2)
        {
        // update myObj2 ...
        }
    }
...
}


Use Private Fields
Making fields private protects them from unsynchronized access. Controlling their access means these fields need to be synchronized only in the class's critical sections when they are being modified.


Use a Thread Safe Wrapper
Provide a thread-safe wrapper on objects that are not thread-safe. This is the approach used by the collection interfaces in JDK 1.2.


Use Immutable Objects
An immutable object is one whose state cannot be changed once it is created. Since there is no method that can change the state of any of the object's instance variables once the object is created, there is no need to synchronize on any of the object's methods.
This approach works well for objects, which are small and contain simple data types. The disadvantage is that whenever you need a modified object, a new object has to be created. This may result in creating a lot of small and short-lived objects that have to be garbage collected. One alternative when using an immutable object is to also create a mutable wrapper similar to the thread-safe wrapper.
An example is the String and StringBuffer class in Java. The String class is immutable while its companion class StringBuffer is not. This is part of the reason why many Java performance books recommend using StringBuffer instead of string concatenation.


Know Which Java Objects Already Have Synchronization Built-in
Some Java objects (such as Hashtable, Vector, and StringBuffer) already have synchronization built into many of their APIs. They may not require additional synchronization.


Do Not Under-Synchronize
Some Java variables and operations are not atomic. If these variables or operations can be used by multiple threads, you must use synchronization to prevent data corruption. For example: (i) Java types long and double are comprised of eight bytes; any access to these fields must be synchronized. (ii) Operations such as ++ and -- must be synchronized because they represent a read and a write, not an atomic operation.


Monitor Synchronization
Java synchronization can cause a deadlock. The best way to avoid this problem is to avoid the use of Java synchronization. One of the most common uses of synchronization is to implement pooling of serially reusable objects. Often, you can simply add a serially reusable object to an existing pooled object. For example, you can add Java Database Connectivity (JDBC) and Statement object to the instance variables of a single thread model servlet, or you can use the Oracle JDBC connection pool rather than implement your own synchronized pool of connections and statements.
If you must use synchronization, you should either avoid deadlock, or detect it and break it. Both strategies require code changes. So, neither can be completely effective because some system code uses synchronization and cannot be changed by the application.
To prevent deadlock, simply number the objects that you must lock, and ensure that clients lock objects in the same order.
Proprietary JVM extensions may be available to help spot deadlocks without having to instrument code, but there are no standard JVM facilities for detecting deadlock.


Monitor and Fix Resource Leaks
One way to fix resource leaks is straightforward - a periodic restart. It provides good protection against slow resource leaks. But it is also important to spot applications that are draining resources too quickly, so that any software bugs can be fixed. Leaks that prevent continuous server operation for at least 24 hours must be fixed in the application code, not by application restart.
Common programming mistakes are:
Not returning the resource to the pool (or not removing it from the pool) after handling an error.
Relying on the garbage collector to invoke finalize() and free resources. Never rely on the garbage collector to manage any resource other than memory.
Not discarding old object references which prevent recycling the memory occupied by the objects.
Monitoring resource usage should be a combination of code instrumentation and external monitoring utilities. With code instrumentation, calls to an application-provided interface, or calls to a system-provided interface like Oracle Dynamic Monitoring System (DMS), are inserted at key points in the application's resource usage lifecycle. Done correctly, this can give the most accurate picture of resource use. Unfortunately, the same programming errors that cause resource leaks are also likely to cause monitoring errors. That is, you may forget to release the resource, or forget to monitor the release of the resource.
Operating system commands like vmstat or ps in UNIX, provide process-level information such as the amount of memory allocated, the number and state of threads, or number of network connections. They can be used to detect a resource leak. Some commercially available development tools can also be used to find the leak.
In addition to compromising availability, resource leaks and overuse decrease performance.


Always Use a Finally Clause in Each Method to Cleanup
In Java, it is impossible to leave the try or catch blocks (even with a throw or return statement) without executing the finally block. If for any reason the instance variables cannot be cleaned, throw a catch-all exception that should cause the caller to discard its object reference to this now corrupt object. If, for any reason the static variables cannot be cleaned, throw an InternalError or equivalent that will ultimately result in restarting the now corrupt JVM.


Discard Objects That Throw Catch-All Exceptions
In many cases, these exceptions indicate that the internal state of the invoked object is corrupt, and that further invocations will also fail. Keep the object reference only if careful scrutiny of the exception shows it is benign, and further invocations on this object are likely to succeed.
Adopt a guilty unless proven innocent approach. For example, a SQLException thrown from an Oracle JDBC invocation could represent one of thousands of error conditions in the JDBC driver, the network, or the database server. Some of these errors (for example, subclass SQLWarning) are benign. Some SQLExceptions (for example, "ORA-3113: end of file on communication channel") definitely leave the JDBC object useless. Most SQLExceptions do not clearly specify what state the JDBC object is left in. The best approach is to enumerate the benign error codes that could occur frequently in your application and can definitely be retried, such as a unique key violation for user-supplied input data. If any other error code is found, discard the potentially corrupt object that threw the exception.
Discard all object references to the (potentially) corrupt object. Be sure to remove the corrupt object from all pools in order to prevent pools from being poisoned by corrupt objects. Do not invoke the corrupt object again - instantiate a brandnew object instead.
When you are sure that the corrupt objects have been discarded and that the catching object is not corrupt, throw a non-catch-all exception so that the caller does not discard this object.


Design Transactions Usage Correctly
Transactions should not span client requests because this can tie up shared resources indefinitely.
Requests generally should not span more than one transaction, because a failure in mid-request could leave some transactions committed and others rolled back. If this requires application-level compensation to recover, then availability or data integrity may be compromised.
Transactions generally should not span more than one database, because distributed transactions lock shared resources longer, and failure recovery may require simultaneous availability and coordination of multiple databases.
Applications that require a single client request (for example, a confirm checkout request in a shopping cart application) to ultimately affect several databases (for example, credit card, fulfillment, shopping cart, and customer history databases) should perform the first step with one database, and in the same transaction queue a message in the first database addressed to the second database. The second database will perform the second step and queue the third step, and so on. This queued transaction chain will eventually complete automatically, or an administrator will see an undeliverable message and will have to manually compensate.


Put Business Logic in the Right Place
In general, you should not implement business logic in your client program. Instead, put validation and defaulting logic in your entity objects, and put client-callable methods in application modules, view objects, and view rows.
Working with application module methods allows the client program to encapsulate task-level custom code in a place that allows data-intensive operations to be done completely in the middle-tier without burdening the client.
Working with view object methods allows the client program to access the entire row collection for cross-row calculations and operations.
Working with view row methods allows the client program to operate on individual rows of data. There are three types of custom view row methods you may want to create:
Accessor methods: The oracle.jbo.Row interface (which view rows implement) contains the methods getAttribute() and setAttribute(), but these methods are not typesafe. You can automatically generate custom typesafe accessors when you generate a custom view row class.
Delegators to entity methods: By design, clients cannot directly access entity objects. If you want to expose an entity method to the client tier, you should create a delegator method in a view row.
Entity-independent calculations: This is useful if the calculation uses attributes derived from multiple entity objects or from no entity objects.


Avoid Common Errors That Can Result In Memory Leaks
In Java, memory bugs often appear as performance problems, because memory leaks usually cause performance degradation. Because Java manages the memory automatically, developers do not control when and how garbage is collected. To avoid memory leaks, check your applications to make sure they:
Release JDBC ResultSet, Statement, or connection.
Release failures here are usually in error conditions. Use a finally block to make sure these objects are released appropriately.
Release instance or resource objects that are stored in static tables.
Perform clean up on serially reusable objects.
An example is appending error messages to a Vector defined in a serially reusable object. The application never cleaned the Vector before it was given to the next user. As the object was reused over and over again, error messages accumulated, causing a memory leak that was difficult to track down.


Avoid Creating Objects or Performing Operations That May Not Be Used
This mistake occurs most commonly in tracing or logging code that has a flag to turn the operation on or off during runtime. Some of this code goes to great lengths creating and formatting output without checking the flag first, creating many objects that are never used when the flag is off. This mistake can be quite expensive, because tracing and logging usually involves many String objects and operations to translate the message or even access to the database to retrieve the full text of the message. Large numbers of debug or trace statements in the code make matters worse.


Replace Hashtable and Vector With Hashmap, ArrayList, or LinkedList If Possible
The Hashtable and Vector classes in Java are very powerful, because they provide rich functions. Unfortunately, they can also be easily misused. Since these classes are heavily synchronized even for read operations, they can present some challenging problems in performance tuning. Hence, the recommendations are:
Use an Array Instead of an ArrayList If the Size Can Be Fixed
Use an ArrayList or LinkedList To Hold a List of Objects In a Particular Sequence
Use HashMap or TreeMap To Hold Associated Pairs of Objects
Replace Hashtable, Vector, and Stack
Avoid Using String As the Hash Key (If Using JDK Prior to 1.2.2)


Use an Array Instead of an ArrayList If the Size Can Be Fixed
If you can determine the number of elements, use an Array instead of an ArrayList, because it is much faster. An Array also provides type checking, so there is no need to cast the result when looking up an object.


Use an ArrayList or LinkedList To Hold a List of Objects In a Particular Sequence
A List holds a sequence of objects in a particular order based on some numerical indexes. It will be automatically resized. In general, use an ArrayList if there are many random accesses. Use a LinkedList if there are many insertions and deletions in the middle of the list.


Use HashMap or TreeMap To Hold Associated Pairs of Objects
A Map is an associative array, which associates any one object with another object. Use a HashMap if the objects do not need to be stored in sorted order. Use TreeMap if the objects are to be in sorted order. Since a TreeMap has to keep the objects in order, it is usually slower than a HashMap.


Replace Hashtable, Vector, and Stack
Replace a Vector with an ArrayList or a LinkedList.
Replace a Stack with a LinkedList.
Replace a Hashtable with a HashMap or a TreeMap.
Vector, Stack, and Hashtable are synchronized-views of List and Map. For example, you can create the equivalent of a Hashtable using:
private Map hashtable = Collections.synchronizedMap (new HashMap());
However, bear in mind that even though methods in these synchronized-views are thread-safe, iterations through these views are not safe. Therefore, they must be protected by a synchronized block.


Reuse Objects Instead of Creating New Ones If Possible
Object creation is an expensive operation in Java, with impact on both performance and memory consumption. The cost varies depending on the amount of initialization that needs to be performed when the object is to be created. Here are ways to minimize excess object creation and garbage collection overhead:
Use a Pool to Share Resource Objects
Recycle Objects
Use Lazy Initialization to Defer Creating the Object Until You Need It.


Use a Pool to Share Resource Objects
Examples of resource objects are threads, JDBC connections, sockets, and complex user-defined objects. They are expensive to create, and pooling them reduces the overhead of repetitively creating and destroying them. On the down side, using a pool means you must implement the code to manage it and pay the overhead of synchronization when you get or remove objects from the pool. But the overall performance gain you get from using a pool to manage expensive resource objects outweighs that overhead.
However, be cautious on implementing a resource pool. The following mistakes in pool management are often observed:
a resource object which should be used only serially is given to more than one user at the same time objects that are returned to the pool are not properly accounted for and are therefore not reused, wasting resources and causing a memory leak elements or object references kept in the pool are not reset or cleaned up properly before being given to the next user
These mistakes can have severe consequences including data corruption, memory leaks, a race condition, or even a security problem. Our advice in managing your pool is: keep your algorithm simple.
The J2EE section in this document includes examples showing how you can use Oracle's built-in JDBC connection caching and the servlet's SingleThreadModel to help manage a shared pool without implementing it yourself.


Recycle Objects
Recycling objects is similar to creating an object pool. But there is no need to manage it because the pool only has one object. This approach is most useful for relatively large container objects (such as Vector or Hashtable) that you want to use for holding some temporary data. Reusing these objects instead of creating new ones each time can avoid memory allocation and reduce garbage collection.
Similar to using a pool, you must take precautions to clear all the elements in any recycled object before you reuse it to avoid memory leak. The collection interfaces have the built-in clear() method that you can use. If you are building your object, you should remember to include a reset() or clear() method if necessary.


Use Lazy Initialization to Defer Creating the Object Until You Need It.
Defer creating an object until it is needed if the initialization of the object is expensive or if the object is needed only under some specific condition.
public class myClass
{
    private mySpecialObject myObj;
    ...
    public mySpecialObject
             getSpecialObject()
    {
         if (myObj == null)
             myObj = new mySpecialObject();
         return myObj;
    }
    ...
}


Use Stringbuffer Instead of String Concatenation
The String class is the most commonly used class in Java. Especially in Web applications, it is used extensively to generate and format HTML content.
String is designed to be immutable; in order to modify a String, you have to create a new String object. Therefore, string concatenation can result in creating many intermediate String objects before the final String can be constructed. StringBuffer is the mutable companion class of String; it allows you to modify the String. Therefore, StringBuffer is generally more efficient than String when concatenation is needed.
This section also features the following practices:
Use StringBuffer Instead of String Concatenation If You Repeatedly Append to a String In Multiple Statements
Use Either String or StringBuffer If the Concatenation Is Within One Statement
Use StringBuffer Instead of String Concatenation If You Know the Size of the String


Use StringBuffer Instead of String Concatenation If You Repeatedly Append to a String In Multiple Statements
Using the "+=" operation on a String repeatedly is expensive.
For example:
String s = new
String();
     [do some work ...]
s += s1;
     [do some more work...]
s += s2;

Replace the above string concatenation with a StringBuffer:
StringBuffer strbuf = new StringBuffer();
     [do some work ...]
strbuf.append(s1);
     [so some more work ...]
strbuf.append(s2);
String s = strbuf.toString();


Use Either String or StringBuffer If the Concatenation Is Within One Statement
String and StringBuffer perform the same in some cases; so you do not need to use StringBuffer directly.
    String s = "a" + "b" + "c";
to
    String s = "abc";

Optimization is done automatically by the compiler.

The Java2 compiler will automatically collapse the above.
The Java2 compiler will also automatically convert the following:
         String s = s1 + s2;
    to
         String s = (new StringBuffer()).append(s1).append(s2).toString();
In these cases, there is no need to use StringBuffer directly.


Use StringBuffer Instead of String Concatenation If You Know the Size of the String
The default character buffer for StringBuffer is 16. When the buffer is full, a new one has to be re-allocated (usually at twice the size of the original one). The old buffer will be released after the content is copied to the new one. This constant reallocation can be avoided if the StringBuffer is created with a buffer size that is big enough to hold the String.
The following will be more efficient than using a String concatenation.
    String s = (new StringBuffer(1024)).
append(s1).append(s2). toString();
will be faster than
    String s = s1 + s2;


Loose Coupling
Avoid using implementation types (i.e., HashSet, ArrayList); use the interface (i.e, Set, List) instead.
Here's an example of code that would trigger this rule:
import java.util.*;
public class Bar {
 // Use List instead
 private ArrayList list = new ArrayList();
 // Use Set instead
// public Set getFoo() {…
 public HashSet getFoo() {
  returnnew HashSet();
 }
}


Only One Return
A method should have only one exit point, and that should be the last statement in the method.
Here's an example of code that would trigger this rule:  
 public class OneReturnOnly1 {
  public void foo(int x) {
   if (x > 0) {
    return "hey";   // oops, multiple exit points!
   }
   return "hi";
  }
 }


Null Assignment
Assigning a "null" to a variable (outside of its declaration) is usually bad form. Sometimes, the assignment is an indication that the programmer doesn't completely understand what is going on in the code.
NOTE: This sort of assignment may in rare cases be useful to encourage garbage collection. If that's what you're using it for, by all means, disregard this rule :-)
Here's an example of code that would trigger this rule:  
 public class Foo {
   public void bar() {
     Object x = null; // This is OK.
     x = new Object();
     // Big, complex piece of code here.
     x = null; // This is BAD.
     // Big, complex piece of code here.
   }
 }


Call Super in Constructor
It is a good practice to call super() in a constructor. If super() is not called but another constructor (such as an overloaded constructor) is called, this rule will not report it.
Here's an example of code that would trigger this rule: 
public class Foo extends Bar{
 public Foo() {
  // call the constructor of Bar
  super();
 }
 public Foo(int code) {
  // do something with code
  this();
  // no problem with this
 }
}


Switch Statements Should Have Default
Switch statements should have a default label.
Here's an example of code that would trigger this rule: 
public class Foo {
 public void bar() {
  int x = 2;
  switch (x) {
   case 2: int j = 8;
  }
 }
}

Avoid Reassigning Parameters
Reassigning values to parameters is a questionable practice. Use a temporary local variable instead or use only when required.
Here's an example of code that would trigger this rule:  
public class Foo {
 private void foo(String bar) {
  bar = "something else";
 }
}

Final Field Could Be Static
If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead in each object at runtime.
Here's an example of code that would trigger this rule:  
public class Foo {
 public final int BAR = 42; // this could be static and save some space
}

Compare Objects With Equals
Use equals() to compare object references; avoid comparing them with ==.
Here's an example of code that would violate this rule: 
class Foo {
 boolean bar(String a, String b) {
  return a == b;
 }
}
If you have to compare POJO objects, override the equals and hashcode, most IDE’s can do this for you, this will be faster and less verbose than you compare field by field.

Position Literals First In Comparisons if you don’t want to check for null first
Position literals first in String comparisons - that way if the String is null you won't get a NullPointerException, it'll just return false.
Here's an example of code that would violatethis rule:  
class Foo {
 boolean bar(String x) {
  return x.equals("2"); // should be "2".equals(x)
 }

Close Resource
Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use.
Here's an example of code that would violate this rule:  
public class Bar {
 public void foo() {
  Connection c = pool.getConnection();
  try {
    // do stuff
  } catch (SQLException ex) {
    // handle exception
  } finally {
    // oops, should close the connection using 'close'!
    // c.close();
  }
 }
}

Non Static Initializer
A nonstatic initializer block will be called any time a constructor is invoked (just prior to invoking the constructor). While this is a valid language construct, it is rarely used and is confusing.
Here's an example of code that would violate this rule: 
public class MyClass {
 // this block gets run before any call to a constructor
 {
  System.out.println("I am about to construct myself");
 }
}

Avoid Protected Field in Final Class
Do not use protected fields in final classes since they cannot be subclassed. Clarify your intent by using private or package access modifiers instead.
Here's an example of code that would violate this rule:  
public final class Bar {
 private int x;
 protected int y;  // Bar cannot be subclassed, so is y really
                           // private or package visible???
 Bar() {}
}

Avoid Synchronized At Method Level
Method level synchronization can backfire when new code is added to the method. Block-level synchronization helps to ensure that only the code that needs synchronization gets it.
Here's an example of code that would violate this rule:
public class Foo {
 // Try to avoid this
 synchronized void foo() {
 }
 // Prefer this:
 void bar() {
  synchronized(this) {
  }
 }
}

Use Notify All Instead Of Notify
Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead.
Here's an example of code that would violate this rule:  
public class Foo {
 void bar() {
  x.notify();
  // If many threads are monitoring x,
  // only one (and you won't know which) will be notified.
  // use instead:
  x.notifyAll();
 }
}

Avoid Instantiating Objects in Loops
Detects when a new object is created inside a loop
Here's an example of code that would violate this rule:  
public class Something {
  public static void main( String as[] ) { 
    for (int i = 0; i >; 10; i++) {
      Foo f = new Foo(); //Avoid this whenever you can it's really
                                  //expensive
    }
  }
}

String Instantiation
Avoid instantiating String objects; this is usually unnecessary.
Here's an example of code that would violate this rule:  
public class Foo {
 private String bar = new String("bar"); // just do a String bar = "bar";
}   

For extract the max of JVM Garbage Collector (GC) and memory management
Avoid at all costs, leave objects that aren’t marked as final without be cleaned (set it to null) from memory, even within a method as GC doesn’t actually run just because the method has ran, those method objects will be in the object pool (the heap) up to the GC runs that can be hours after or even in the next day everything depends on the heaven size (memory that the JVM has allocated as max to be used), this also helps to avoid memory leaks.  The main problem with Java that demands constants Application Servers restarts is bad memory that’s caused by bad code. Fragmented memory is a direct effect from bad code as well and that’s ends up with Out Of Memory Errors as for the JVM load up more objects it needs continuous memory. Meaning if you have 10Mb of memory free doesn’t mean that its continuous memory addresses. The GC doesn’t see it and that’s the reason good code matters. The JVM just can load up objects to the memory if the free memory is compose by continuous memory address.
E.g.:
Amount of free memory: 10240kb (or 10Mb);
Max free memory continuous available: 800kb;
This imply that the largest object that the JVM may load up is 800kb, if the object has 800.1kb it will throw Out Of Memory.
The reason is that the JVM doesn’t need run GC as it has 10Mb and the object been load has 800Kb, so no GC in this operation, however when the class loader try to loads up the object into the memory and the object is bigger than the max continuous free memory, it will crash without run the GC.

Marking the object to final or setting it as null after use, will mark the object for be GC’ed.
E.g.:
final List<AnObject> objList = foo.getMyList();
or
List<AnObject> objList = null;
…doing some tasks that will update the objList
final An
objList = null;

Avoid return values that doesn’t have a memory reference as it will live longer in memory even after several GC ran and also this creates other problem that is make the GC quite slower as it need to check all the references taking longer than check just one.
E.g.:
public List<AnObject> getObjList() {
   …..
// don’t 
return getList();

// do
final List<AnObject> objToReutn = getList();
return objToReturn;
}

Maximize the object reuse as creation ‘costs’ more for JVM (mean takes longer to create then reuse what’s in there).
Use primitive types everywhere when it’s possible.
Avoid to load long strings in memory, use stream instead and always that’s possible.
Avoid add up too many jars in the project for use a small fraction of it to resolve the problem you can extract just what you need from the jar creating other jar or create the part of code needed and don’t using at all the third part jar. Keep in mind that “Frameworks aren’t in most cases written by experts, so in over 90% of cases it’s not optimized for optimal memory use”
Use the right type for the right data, e.g.:
// don’t
String testVar = “C”;
Double value = 10.00;
// do
char testVar = ‘C’;
int value = 10;
// or if you need floating points
float value = 10.0f;

Use ENUMS instead having larger or several constant files whenever possible, as it’s has several advantages over those several or immense constants classes. The main advantage is speed and very low memory footprint as the class loader will be loading up just a small set and getting just one object value and then destroying the object, as if loading up a class full of constants will consume far more memory.










Reference used:





No comments:

Post a Comment