As one of the most popular development languages in the world, Java is expanding its territory ferociously, from microcontroller to Android, Java can be seen everywhere. As more and more people joined the Java development environment, the class divide became apparent. Great god and rookie, often only a line between, today xiaobian will put this layer of window paper poke.

In development, the “666”, as it’s called, is often just a few keyboard shortcuts away. There are a few simple techniques and development habits that can go a long way in getting things done.

Avoid creating objects repeatedly

Why is that?

Fewer objects require less garbage collection

The less space you use, the better your application will perform

How to do?

Reuse an object instead of creating a functional object every time you need it

(To do so)

String s = “No longer silly”;

(Don’t do it)

String s = new String(” silly “);

Immutable classes that provide both constructors and static factory methods are preferred. Reuse objects that will not change once they are initialized (using static initialization). +++

Avoid circular references

why

A set of objects that refer to each other can become unreachable if they are not directly referenced by other objects, causing them to remain in memory forever.

How to do

You can use strong references for parent-to-child references and weak references for child-to-parent references.

Learn about JVM memory management

why

Some argue that Java programmers don’t need to know about internal JVM memory management. Without a doubt, this view is clearly wrong, and you must learn about JVM memory management if you want to broaden your knowledge and improve your troubleshooting skills

How to do?

JVM memory is divided into three memory Spaces

Java Heap: Applies to all JVM vendors and is typically used to split YoungGen(seedling) and OldGen(lifetime) Spaces.

PermGen(Permanent generation) : for SunHotSpot VM(PermGen space will be removed in Java7 or Java8 update)

Native Heap(C-heap) : Available for all JVM vendors. As you can see, JVM memory management is more complex than setting maximum values using Xmx. You need to look at every Angle, including local and PermGen requirements as well as physical memory availability (CPU core) from the host.

Use the == operator instead of equals(Object)

why

The == operator performs better

For example, for string comparisons, equals() compares characters in string objects. The == operator compares references to two objects to see if they refer to the same instance.

What to do:

A. quals(b) exists if and only if a== B

For example, use the static factory method to return the same object for repeated calls.

Avoid using Finalizer

why

The garbage collector needs to keep separate records of the objects awaiting finalization

Calling the Finalize method also has some overhead

Finalizers are unsafe because they may resurrect an object, which interferes with garbage collection.

Avoid using reference objects

why

Like Finalizers, garbage collectors need to specifically handle soft references, weak references, and ghost references.

Although reference objects are useful in some ways, such as simplifying cache implementation, the presence of a large number of reference objects can make garbage collection slow.

The overhead of recording a reference object is much higher than that of a normal object (strong reference).

Avoid object pooling

why

Object pooling not only keeps more data objects active, but also makes them live longer.

It is worth noting that the processing of large numbers of live data objects is a bottleneck for GC, which is optimized to handle many short-lived objects

Also, creating new objects rather than keeping old ones alive can benefit the locality of the cache.

However, in an environment with a large number of objects, such as large arrays, performance might be improved by using object pools.

Choose good algorithms and data structures

why

Consider a scenario where queues are implemented through linked lists

Even if your program doesn’t need to traverse the entire list, the garbage collector does.

This can break cache locality if the element wrapper does not place the element in an adjacent location in memory. This can lead to long program pauses, especially if Pointers to objects are scattered over a large heap, and the garbage collector frequently experiences cache invalidation during the marking phase following Pointers.

Avoid system.gc

why

There is no guarantee in the Java language specification that calling System.gc will do anything. If it does, it might exceed your expectations, or it might do something different with each call.

Avoid using too many threads

why

The number of process context switches increases with the number of processes to be scheduled, which has a hidden impact on performance.

For example, the size of a local thread context on an IntelA-64 processor is in the thousands of kilobytes.

Review static occupancy requirements

why

Try to get a reasonable estimate of static memory footprint, and it is useful to set some starting points for JVM capabilities before actually testing the data.

How to do

The application and associated data will determine the Java heap space footprint requirements. With static memory, the following memory requirements can be predicted:

Determine how many different applications will be deployed on a single, pre-planned JVM process, and how many classes will need to be loaded at run time: including third-party apis. Determine data cache footprint, such as application loading internal cache data structures (and third-party apis). Determines the number of middleware threads allowed to be created.

The more applications deployed on the JVM process, the higher the requirements on local memory and PermGen space. The data cache is not serialized to a disk or database, it will require additional memory from OldGen space. Try to get a reasonable estimate of static memory footprint, and it is useful to set some starting points for JVM capabilities before actually testing the data. For 32-bit JVMS, it is generally not recommended to have a Java heap size greater than 2GB(-xMS2048m, -XMX2048m), which will require sufficient memory and native heap PermGen for JavaEE applications and threads. This assessment is important because too many applications deployed on a 32-bit JVM process can easily lead to native heap exhaustion; Especially in a multi-threaded environment. For 64-bit JVMS, a 3GB or 4GB Java heap /JVM process is the recommended starting point.

Avoid unwanted exceptions

why

Exception handling takes up a number of events and interrupts the normal execution of the program.

The author once encountered a scenario where a normal execution process in a client’s application would throw thousands of NullPointerExceptions per second. When this error was corrected, there was an order of magnitude improvement in application performance.

Avoid large objects

why

Large objects sometimes need to be allocated directly in the heap rather than in Thread local areas (TLA).

It is bad for large objects to be allocated directly on the heap because it generates memory fragmentation more quickly. Allocating large objects on virtual machines (such as JRockit) degrades performance because memory is allocated using a global lock on the heap.

Overuse of large objects can cause frequent full-stack compression, which is destructive, and can cause all threads to pause for long periods of time.