Can memory leak occur in Java?

Asked

Viewed 720 times

6

In the C language, for example, memory leaks are common because the responsibility for shifting memory lies with the programmer. In the example below (taken from Wikipedia) we can see a classic situation of memory leakage.

#include <stdlib.h>

void funcao_que_aloca(void) {
    /* aloca um array de 45 floats */
    float *a = malloc(sizeof(float) * 45);

    /* volta pro main sem liberar memória */
}

int main(void) {
    funcao_que_aloca();

    /* o ponteiro 'a' não existe mais, mas a memória continua alocada*/
}

Since in Java we have Garbage Collector and the responsibility to free the memory does not stay with the programmer, how safe is it to say that applications in Java are free of memory leakage? Do they exist? If so, is there any specific precaution to avoid the problem?

  • Have any answers solved what was in doubt? Do you need something else to be improved? Do you think it is possible to accept it now?

2 answers

6

What is memory leakage?

First we need to define what memory leakage is.

Technically Java can not have leaks if considering that the leak only occurs when something is allocated and never occurs the possibility of release when there are no more references to this object.

If you consider that leaking is all memory occupied without having a reference to that object, then Java leaks memory all the time. Only it will not have leaked memory when the GC runs and clear all that there are no more references. Soon after it starts leaking again. If you do not consider this a leak, we still have the definition that Java never leaks memory.

If you consider leakage is when you have a referenced object still somewhere, but this object will no longer be used in the application, then leakage occurs and may be for several reasons. But many people do not consider this leak since the object is referenced.

Forms of leakage

  • An object can continue to be referenced without use if it is attached to a static variable directly or indirectly (see below). But if you’ve defined that he’s static, that’s probably what you want, isn’t it? If it isn’t, you made a mistake, but I wouldn’t call it a memory leak, it’s a misguided engineering.

  • If an object is attached to an instance and that instance for some reason never dies, then the reference to it never dies either. Some people say it’s memory leakage, I keep thinking it’s engineering error, if it’s not a real need, and if it’s a need, then it’s okay.

  • If you have a method in a thread running in parallel and it is running all the time, and in this method has a local variable that references an object that is no longer used after some operation. It would be a memory leak?

    Actually with threads has a lot of situation that it is easy to keep references longer than you want.

  • When does interning of string is like having a static object.

  • When you open a resource and it doesn’t close, the object is allocated in unmanaged memory and is there without collection. That’s why it is recommended to always open with try-resource. This would clearly be a leak, but the GC can handle it if there are no references.

  • When you make a pool of objects you may be holding other objects referenced there. That is, an object in the pool is no longer in use, but he is alive, and all that is attached to him and also serves no purpose for anything else is still alive. It might be considered memory leakage, but I still think it’s engineering error, or normal mechanism behavior.

  • Something similar may occur with cache, but is more rare. Properly cached has weak references, so its release can occur easily.

  • Use sun.misc.Unsafe you may have a leak, after all it allows you to access the memory in an unmanaged way.

  • There is a list of algorithms that holds a reference where it should not, but you do not want to list several examples here, right?

    In general this occurs when you take an element of a array or a class and thinks you’re copying it, when you’re actually referencing the element. Then you may no longer have any reference to the tip of array huge, but still has a reference to an element of it. The array cannot be released. Technically this is not memory leak, but the effect is very similar. The right one is to copy the contents of the reference.

    That goes for any kind of array, including String. A simple and seemingly harmless substring() can hold a reference longer than you want. You carry a book, make a substring() in a word and ready, the book can no longer be released until the variable holding that word is released, even if nothing else references the book (it seems that this no longer occurs in recent versions, but it has created other new problems).

    In Java this is mostly because almost everything is reference (this will start to change in Java 10).

  • What is consumed by the JVM itself and is not released, can be considered memory leakage?

Nor will I speak of those corner cases that can occur in a very forced way, practically exploiting a gap that is even difficult to reproduce.

How to solve

There are cases where you need to manually override a variable to release the reference, but I usually say that if you did this there is probably something wrong with the code. There may be some reason to do so, but almost always it is gambiarra.

In general it is necessary to know the language well, the libraries you are using and be attentive to what you are doing. Contrary to what many people regret, GC does not eliminate the need to think about memory management.

Releasing memory is not your concern, releasing references remains your responsibility. It will not go away giving null everywhere.

Decrease the amount of allocations is still interesting to have a more efficient application and Java has finally started taking this path.

-1

It can occur even with the existence of Garbage Collector (GC). Usually, memory leaks in Java will occur due to programming errors.

For example, a simple example that generates memory leakage:

public Object pop() {
if (size == 0)
    throw new EmptyStackException();
return elements[--size];

}

The above code removes an element from the stack. For example, if you use the pop() method in Elements[5], it will result in Elements[4]. However, objects removed from the stack will not be collected by GC. Obsolete references of Elements[5] will remain even after pop() that will be ignored by the GC and all existing references linked to the mentioned object will also continue to exist, considerably hindering the performance of its application.

A correction to the above method would be to undo references when they become obsolete, as follows in the example below:

public Object pop() {
if (size == 0)
    throw new EmptyStackException();

Object result = elements[--size];
elements[size] = null;
return result;
}

The following is an article from Devmedia, that contains the example cited above and answers your question more fully.

  • Not disqualifying your answer, but it would be interesting to transcribe briefly the explanation of the link here, so that, if it comes off the air, the answer is not invalid.

  • Thank you so much for the diegofm tip. I brought a simple example and a brief explanation of the cited article to not occur what you quoted.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.