Tips to Manage Garbage Collection in Java


With each evolution, garbage collectors get new improvements and advancements. However, garbage collections in Java face a common issue: unpredictable and redundant object allocations. Consider the following tips to improve your garbage collection in Java.

1.   Estimate Capacity of the Collections

All types of Java collections including extended and custom implementations take advantage of underlying object-based or primitive arrays. Due to the size immutability of arrays after allocation, when items are added to a collection, a new array can force the old array to get dropped.

Many implementations of collections attempt optimization of the re-allocation process and try to limit it an amortized restriction, whether or not the expected collection size is not given. To get the best results, give the collection its expected size during creation.

For instance, consider the following code.

public static List reverse(List < ? extends T > list) {

List answer = new ArrayList();

for (int x = list.size() – 1; x > = 0; x–) {

answer.add(list.get(x));

}

return answer;

}

In this method, a new array is allocated after which another list’s items fill it via a reverse order. In this code, optimization can be applied to the specific line which performs addition of items in the new list. Whenever an item is added, the list has to ensure that there are enough available slots in the underlying array so it can store the incoming item. If there is a free slot, then it can easily store it. Or else, it has to perform allocation of a new underlying array, move the content of the old array to the newer one, and then perform the addition of the new item. As a result, multiple arrays are allocated which are ultimately collected by the garbage collection.

In order to avoid these redundant and inefficient allocations, you can “inform” the array about the number of items it can store while creating it.

public static List reverse(List < ? extends T > list) {

 

List answer = new ArrayList(list.size());

 

for (int x = list.size() – 1; x > = 0; x–) {

answer.add(list.get(x));

}

return answer;

}

As a result, the first allocation from the constructor of the ArrayList is big enough to store the items of the list.size(), thus there is no need for reallocation of memory in the middle of an iteration.

2.   Compute Streams with a Direct Approach

While data is being processed like it is downloading from the network or read from the file, then it not uncommon to view the following instances.

byte[] fData = readFileToByteArray(new File(“abc.txt”));

As a result, the byte array a JSON object, XML document, or Protocol Buffer message can then be used for parsing. While working with bigger files or files having uncertain size, there are possibilities of exposure to OutOfMemoryErrors if buffer allocation of the complete file is not performed by the Java Virtual Machine.

In case, we assume that the data size can be managed, the above-mentioned pattern can lead on to generate considerable overhead for garbage collection because a huge blob is allocated on the heap for holding the data of the file.

There are better solutions to tackle this. One of them is the use of the relevant InputStream and use the parser directly before converting it into a byte array. Usually, all crucial libraries are known to have API exposure for direct streams parsing. For instance, consider the following code.

FileInputStream fstream =new FileInputStream(fileName);

MyProtoBufMessage message = MyProtoBufMessage.parseFrom(fstream);

3.    Make Use of Immutable Objects

Immutability brings a lot of benefits to the table. Perhaps, its biggest one is on the garbage collection. An object in which you cannot alter the fields after the construction of the project is known as an immutable object. For instance,

public class twoObjects {

private final Object a;

private final Object b;

public twoObjects(Object a, Object b) {

this.a = a;

this.b = b;

}

public Object getA() {

return a;

}

public Object getB() {

return b;

}

}

The instantiation of the above-mentioned class provides an immutable object in which all the fields are set as ‘final’ and cannot be altered.

Immutability means that objects which are referenced via an immutable container are generated prior to the container’s construction. In terms of garbage collection, the container and the reference have the same age.

Therefore, while working with cycles of garbage collections for young generations, the garbage collection can ignore the older generations’ immutable objects as they are unable to reference.

When there are lesser objects for scanning, it requires less memory and also saves up on garbage collection cycles, resulting in improved throughput.

4.   Leverage Specialized Primitive Collections

The standard collection library of Java is generic and convenient. It assists in using semi-static type binding in collections. This can be advantageous if, for instance, you have to use a string set or work with a map for strings lists.

The actual issue emerges when developers have to store a list contains “ints” or a map containing type double values. As it is not possible to use primitives with generic types, another option is the use of boxed type.

Such an approach consumes a lot of space because an Integer is an object having a 12-byte header and a 4-byte int field. In total each Integer item amounts to 16 bytes—four times the size of the similar primitive int data type. There is another issue that the object instances of these integers have to be assessed for garbage collection.

To resolve this issue, you can use the Trove collection library. It provides a few generics over specialized primitive collections that are memory efficient. For instance, rather than using the Map<Integer, Double>, you can use the TIntDoubleMap.

TIntDoubleMap mp = new TIntDoubleHashMap();

mp.put(6, 8.0);

mp.put(-2, 8.555);

The underlying implementation from Trove works with primitive arrays, hence no boxing occurs during the manipulation of collections and objects are not hold in the primitives’ place.

 

 

 

Advertisement

Serverless Predictions for 2019


Are you using a serverless architecture?

As it was seen in 2018, more and more businesses are coming to serverless computing, especially to Kubernetes. Many of them have even started reaping the benefits of their efforts. Still, the serverless era has just started. In 2019, the following trends are going to change how the organizations create and deploy software.

Adoption in the Enterprise Software

In 2018, serverless computing and FaaS (function as a service) began to become popular among organizations. By the end of 2019, these technologies will go onto the next level and are poised to get adopted on a wider scale, especially for the enterprise application sector. As container-based applications—using the cloud-native architecture—are spreading with a rapid pace, it has served as a catalyst for the burgeoning adoption of serverless computing.

Today, software delivery and deployment has evolved to a great extent. The robustness and range of containers increased the cloud-native applications to unprecedented heights for legacy applications and Greenfield. As a result, business scenarios in which earlier there was not much progress for cloud-native modernization—like data in transit, edge devices, and stateful applications—can be converted into cloud-native. While container-based and cloud-native systems are beginning to experience a rise, software developers are using serverless functions for performing a wide range of tasks across various types of applications. Teams will now deliver microservices transition on a large scale—some may use FaaS to decrease the application’s complexity.

Workflows and similar high-end functionalities in FaaS are expected to provide convenience in creating complicated serverless systems via a composable and modular approach.

Kubernetes as the Defacto Standard

There are fewer better infrastructures than Kubernetes for working with serverless computing. By 2018, Kubernetes was widely used with container orchestration with different cloud providers. As a result, it is the leading cloud-native systems’ enabler and is on its way to becoming the defacto operating system. Ubiquity assists Kubernetes to be transformed into the default standard which can be used for powering serverless systems.

Kubernetes helps to easily create and run those applications in serverless architecture which can utilize cluster management, scaling, scheduler, networking, service discovery, and other powerful built-in features of Kubernetes. Serverless runtime needs these features with interoperability and portability for any type of environment.

Due to Kubernetes position as the standard for the serverless infrastructure, organizations can make use of their own multi-cloud environments and data centers for running serverless applications, rather than being restricted with a single cloud service and face excessive cloud expenses. When organizations will take advantage from cost savings, speed, and enhanced serverless functionality with their own data centers while at the same t time in different environments, they can port serverless applications, then the end result is impactful—the serverless adoption in the enterprise gets a massive boost. It not only becomes a strong architecture for the acceleration of new applications’ development, but it is also a worthy pattern which can help to modernize legacy applications and brownfield.

In cloud-native architecture, the increased refinement of Kubernetes deployments means that you can foresee the Kubernetes-based FaaS frameworks to be integrated with chaos engineering and service meshes concepts. To put it simply, if we consider the next Kubernetes as the next Linux, then serverless can be considered as the modern Java Virtual Machine.

Serverless with the Stateful Applications

Stateless applications with short life spans are used mainly by serverless applications. However, you can now also expect a more rapid serverless adoption having stateful scenarios—which are powered by improvements in advancements in both Kubernetes-based storage systems and serverless systems.

These workloads can consist of validation and test of machine learning applications and models which execute high-end credit checks. Workflows are going to be a major serverless consideration which can make sure that all the use cases only are not only executed properly but can also scale according to requirements.

Serverless Tooling Enters a New Age

Lack of tooling has been an issue for FaaS and serverless computing for a long time. This encompasses the operational and developer team ecosystem support and tooling. In 2019, the major FaaS projects are expected to take a more assembly line tooling view while using the enhanced experience of the developer, and smooth pipelining and live-reload.

In 2019, GitOps will achieve newfound recognition as a FaaS development paradigm. Hence, now all the artifacts can use Git for versioning and roll forwards or rollbacks can resolve the common versioning issues.

Cost Is Going to Raise Eyebrows

As the graph of last years suggests more and more enterprises are going to use serverless architectures to power mission-critical and large-scale applications; thus this also stretches the expenses and costs of serverless computing for public clouds. Consequently, cloud-lock is also expected to become a significant concern.

By the end of 2019, organizations will manage cloud expenses and provide portability and interoperability via standardization on those serverless systems that are open source—similar to Kubernetes. They can also make use of the strategies for utilizing the most efficient cloud provider while avoiding reliance on re-coding while at the same time serverless is being run via private clouds. This can have a major effect and help to enhance resource utilization and improve the current infrastructure. The impact will also touch the investment which was put in on-premise data centers for delivering the identical experience of developers and cloud operations—like how it works in the public cloud.

Before the start of 2020, it can be expected that these 2019 predictions will serve as the foundation of adoption of serverless architecture. All the single applications will be modeled in terms of services, triggers will be used for execution, and they run till the service request is satisfied. As a result, the model can simply how to code software along with ensuring that quick speed is also possible while keeping in mind both the expenses and security of the software.