Does this Java example cause a memory leak? - java

I have a simple example. The example loads an ArrayList<Integer> from a file f containing 10000000 random integers.
doLog("Test 2");
{
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
List<Integer> l = (List<Integer>) ois.readObject();
ois.close();
fis.close();
doLog("Test 2.1");
//l = null;
doLog("Test 2.2");
}
doLog("Test 2.3");
System.gc();
doLog("Test 2.4");
When I have l = null, I get this log:
Test 2 Used Mem = 492 KB Total Mem = 123 MB
Test 2.1 Used Mem = 44 MB Total Mem = 123 MB
Test 2.2 Used Mem = 44 MB Total Mem = 123 MB
Test 2.3 Used Mem = 44 MB Total Mem = 123 MB
Test 2.4 Used Mem = 493 KB Total Mem = 123 MB
But when I remove it, I get this log instead.
Test 2 Used Mem = 492 KB Total Mem = 123 MB
Test 2.1 Used Mem = 44 MB Total Mem = 123 MB
Test 2.2 Used Mem = 44 MB Total Mem = 123 MB
Test 2.3 Used Mem = 44 MB Total Mem = 123 MB
Test 2.4 Used Mem = 44 MB Total Mem = 123 MB
Used Memory is calculated by: runTime.totalMemory() - runTime.freeMemory()
Question: In case where l = null; is present, is there a memory leak?
l is inaccessible, so why can't it be freed?

There is no memory leak in the above code.
As soon as you leave the code block enclosed in {}, the variable l falls out of scope, and the List is a candidate for garbage collection, regardless of if you set it to null first or not.
However, after the code block and until the return of the method, the List is in a state called invisible. While this is true, the JVM is unlikely to automatically null out the reference and collect the List's memory. Therefore, explicitly setting l = null can help the JVM collect the memory before you do your memory calculations. Otherwise, it will happen automatically when the method returns.
You will probably get different results for different runs of your code, since you never know exactly when the garbage collector will run. You can suggest that you think it should run using System.gc() (and it might even collect the invisible List even without setting l = null), but there are no promises. It is stated in the javadoc for System.gc():
Calling the gc method suggests that the Java Virtual Machine expend
effort toward recycling unused objects in order to make the memory
they currently occupy available for quick reuse. When control returns
from the method call, the Java Virtual Machine has made a best effort
to reclaim space from all discarded objects.

I think there's a bit of semantics issue here. "Memory leak" generally means having some data stored in memory by a program (piece of software, etc) and getting that program into a state where it can no longer access that in-memory data to clean it up, thus getting into a situation where that memory cannot be claimed for future use. This, as far as I can tell, is the general definition.
A real-world use of the term "memory leak" is usually in reference to programming languages where it's up to the developer to manually allocate memory for the data that he intends to place on the heap. Such languages are C, C++, Objective-C (*), etc. For example the "malloc" command or the "new" operator both allocate memory for an instance of a class that will be placed in the heap memory space. In such languages, a pointer needs to be kept to those thusly allocated instances, if we later-on want to clean up the memory used by them (when they're no longer needed). Continuing on the above example, a pointer referencing an instance that has been created on the heap using "new" can later on be "removed" from memory by using the "delete" command and passing it the pointer as parameter.
Thus, for such languages, a memory leak usually means having data placed on the heap and subsequentlly either:
arriving into a state where there's no longer a pointer to that data
or
forgetting/ignoring to manually "de-allocate" that on-the-heap data (via it's pointer)
Now, in the context of such a definition of "memory leak" this can pretty much never happend with Java. Technically, in Java it's the Garbage Collector's task to decide when heap-allocated instances are no longer referenced or fall out of scope and clean them up. There's no such equivalent of the C++ "delete" command in Java that would even allow the developer to manually "de-allocate" instances/data from the heap. Even making all the pointers of an instance null will not immediatelly free up that instance's memory, but instead it will only make it "garbage collectable" leaving it to the Garbage Collector thread(s) to clean it up when it makes its sweeps.
Now, one other thing that can happen in Java is to never let go of pointers to certain instances, even though they will no longer be needed after a given point. Or, to give certain instance a scope that's too big for what they are used. This way, they will hang around in memory longer than needed (or forever, where forever means until the JDK process is killed) and thus not have them collected by the Garbage Collector even though from a functional stand-point they should be cleaned up. This can lead to behaviour similar to a "memory leak" in the broader sense where "memory leak" simply stands for "having stuff in memory when it's no longer needed and having no way to clean it up".
Now, as you can see, "memory leak" is somewhat vague, but from what I can see, your example doesn't contain a memory leak (even the version where you don't make l=null). All your variables are in a tight scope as delimited by the accolade block, they are used inside that block and will fall out of scope when the block ends, thus they'll be Garbage Collected "properly" (from the functional stand-point of your program). As #Keppil states: making the pointer null will give the GC a better hint as to when to clean up it's corresponding instance, but even if you never make it null, your code will not (un-necessarely) hang on to instances, so no memory leak there.
A typical example of Java memory leak is when having code deployed into a Java EE application server, such that it will spawn threads outside the control of said application server (imaging a servlet that starts a Quartz job). If the application is deployed and undeployed multiple times, it's possible that some of the threads will not be killed at undeploy time, but also (re) started at deploy time, thus leaving them and any instances they might have created hang uselessly in memory.
(*) The later versions of Objective-C also give the possibility to have heap memory managed automatically, in a fashion similar to Javas Garbage Collection mechanism.

The real answer is that unless the code is JIT'd all local variables are 'reachable' within the method body.
Morealso, curly brackets do absolutely nothing in the bytecode. They exist only in the source level - JVM is absolutely unaware of them. Setting l to null effectively frees the reference up off the stack, so it's GC'd for real. Happy stuff.
If you used another method instead of an inline block everything would have passed w/o any surprises.
If the code is JIT'd and the JVM compiler has built reaching-definitions (also this) most likely setting l=null would have no effect and memory be freed in either case.

Question: In case of removing l = null; (do not have this line of
code), is this a memory leak?
No, but it facilitates the gc in claiming the memory if you do this "pattern"

Related

How does GC stop newly created memory/objects from cleaning up during a GC Cycle (Java/C#)

Suppose we take a sample code as below
class Employee
{
int id;
String name;
}
Employee e = new Employee(1, "NewEmployee");
In the above code, I'm assuming the allocation of heap memory for Employee Object happens first and then its reference is assigned to the stack reference e.
Is the above valid or something deep happens here?
If Yes, Then lets assume right after the memory creation in heap and just before its reference is assigned to e, a GC kicks in and identifies there are no references to this new Heap memory from GC roots.
Would GC Clean this resource up?
Is there a way JVM/CLR handles these scenario's and avoid this kind of Memory corruption?
Tagging both Java & C#, as I see the logic of cleaning up in case of Mark and Sweep for both Java and C# seems to be almost same (at least in terms of identifying unused object from roots & cleaning up).
Then lets assume right after the memory creation in heap and just before its reference is assigned to e, a GC kicks in and identifies there are no references to this new Heap memory from GC roots
This is the wrong assumption, GC simply won't kick in in the middle of such assignment. Obviously, it would be incorrect and dangerous behavior.
And more generally, when JITtting methods, "safe-points" are injected where GC may kick in. Those are typically sub-methods calls, long loops and others (it strictly depend on JIT implementation).
Not sure about JVM but in case of CLR it is hard to see such "GCInfo" about safe-points, even if you will grab the generated assembly code (for example by using https://sharplab.io). I am not aware of any tool other than WinDbg to see it.

Calculate total time an object lasted from its creation to garbage collection

In Effective Java 3rd edition, on page 50, author has talked about total time an object lasted from its creation to the time it was garbage collected.
On my machine, the time to create a simple AutoCloseable object, to close
it using try-with-resources, and to have the garbage collector reclaim it is about
12 ns. Using a finalizer instead increases the time to 550 ns.
How can we calculate such time? Is there some reliable mechanism for calculating this time?
The only reliable method I am aware of (I being emphasized here) is in java-9 via the Cleaner API, something like this:
static class MyObject {
long start;
public MyObject() {
start = System.nanoTime();
}
}
private static void test() {
MyObject m = new MyObject();
Cleaner c = Cleaner.create();
Cleanable clean = c.register(m, () -> {
// ms from birth to death
System.out.println("done" + (System.nanoTime() - m.start) / 1_000_000);
});
clean.clean();
System.out.println(m.hashCode());
}
The documentation for register says:
Runnable to invoke when the object becomes phantom reachable
And my question was really what is phantom reachable after all? (It's a question I still doubt I really understand it)
In java-8 the documentation says (for PhantomReference)
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An
object that is reachable via phantom references will remain so until all
such references are cleared or themselves become unreachable.
There are good topics here on SO that try to explain why this is so, taking into consideration that PhantomReference#get will always return null, thus not much use not to collect them immediately.
There are also topics here (I'll try to dig them up), where it is shown how easy is to resurrect and Object in the finalize method (by making it strongly reachable again - I think this was not intended by the API in any way to begin with).
In java-9 that sentence in bold is removed, so they are collected.
Any attempt to track the object’s lifetime is invasive enough to alter the result significantly.
That’s especially true for the AutoCloseable variant, which may be subject to Escape Analysis in the best case, reducing the costs of allocation and deallocation close to zero. Any tracking approach implies creating a global reference which will hinder this optimization.
In practice, the exact time of deallocation is irrelevant for ordinary objects (i.e. those without a special finalize() method). The memory of all unreachable objects will be reclaimed en bloc the next time the memory manager actually needs free memory. So for real life scenarios, there is no sense in trying to measure a single object in isolation.
If you want to measure the costs of allocation and deallocation in a noninvasive way that tries to be closer to a real application’s behavior, you may do the following:
Limit the JVM’s heap memory to n
Run a test program that allocates and abandons a significant number of the test instances, such, that their required amount of memory is orders of magnitude higher than the heap memory n.
measure the total time needed to execute the test program and divide it by the number of objects it created
You know for sure that objects not fitting into the limited heap must have been reclaimed to make room for newer objects. Since this doesn’t apply to the last allocated objects, you know that you have a maximum error matching the number of objects fitting into n. When you followed the recipe and allocated large multiples of that number, you have a rather small error, especially when comparing the numbers reveals something like variant A needing ~12 ns per instance on average and variant B needing 550 ns (as already stated here, these numbers are clearly marked with “on my machine” and not meant to be reproducible exactly).
Depending on the test environment, you may even have to slow down the allocating thread for the variant with finalize(), to allow the finalizer thread to catch up.
That’s a real life issue, when only relying on finalize(), allocating too many resources in a loop can break the program.

Where is the OutOfMemoryError object created in Java

An OutOfMemoryError occurs when the heap does not have enough memory to create new objects. If the heap does not have enough memory, where is the OutOfMemoryError object created. I am trying to understand this, please advise.
Of course, this is an implementation-dependent behavior. HotSpot has some heap memory inaccessible for ordinary allocations, the JVM can use to construct an OutOfMemoryError in. However, since Java allows an arbitrary number of threads, an arbitrary number of threads may hit the wall at the same time, so there is no guaranty that the memory is enough for constructing a distinct OutOfMemoryError instance for each of them.
Therefore, an emergency OutOfMemoryError instance is created at the JVM startup persisting throughout the entire session, to ensure, that the error can be thrown even if there is really no memory left. Since the instance will be shared for all threads encountering the error while there’s really no memory left, you will recognize this extraneous condition by the fact that this error will have no stack trace then.
The following program
ConcurrentHashMap<OutOfMemoryError,Integer> instances = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newCachedThreadPool();
executor.invokeAll(Collections.nCopies(1000, () -> {
ArrayList<Object> list = new ArrayList<>();
for(;;) try {
list.add(new int[10_000_000]);
} catch(OutOfMemoryError err) {
instances.merge(err, 1, Integer::sum);
return err;
}
}));
executor.shutdown();
System.out.println(instances.size()+" distinct errors created");
instances.forEach((err,count) -> {
StackTraceElement[] trace = err.getStackTrace();
System.out.println(err.getClass().getName()+"#"+Integer.toHexString(err.hashCode())
+(trace!=null&&trace.length!=0? " has": " has no")+" stacktrace, used "+count+'x');
});
running under jdk1.8.0_65 with -Xmx100M and waiting half a minute gave me
5 distinct errors created
java.lang.OutOfMemoryError#c447d22 has no stacktrace, used 996x
java.lang.OutOfMemoryError#fe0b0b7 has stacktrace, used 1x
java.lang.OutOfMemoryError#1e264651 has stacktrace, used 1x
java.lang.OutOfMemoryError#56eccd20 has stacktrace, used 1x
java.lang.OutOfMemoryError#70ab58d7 has stacktrace, used 1x
showing that the reserved memory could serve the construction of four distinct OutOfMemoryError instances (including the memory needed to record their stack traces) while all other threads had to fall back to the reserved shared instance.
Of course, numbers may vary between different environments.
It's generated natively by the JVM, which isn't limited by -Xmx or other parameters. The heap reserved for your program is exhausted, not the memory available for the JVM.

Understanding Java Memory Management

Java programmers know that JVM runs a Garbage Collector, and System.gc() would just be a suggestion to JVM to run a Garbage Collector. It is not necessarily that if we use System.gc(), it would immediately run the GC.Please correct me if I misunderstand Java's Garbage Collector.
Is/are there any other way/s doing memory management other than relying on Java's Garbage Collector?If you intend to answer the question by some sort of programming practice that would help managing the memory, please do so.
The most important thing to remember about Java memory management is "nullify" your reference.
Only objects that are not referenced are to be garbage collected.
For example, objects in the following code is never get collected and your memory will be full just to do nothing.
List objs = new ArrayList();
for (int i = 0; i < Integer.MAX_VALUE; i++) objs.add(new Object());
But if you don't reference those object ... you can loop as much as you like without memory problem.
List objs = new ArrayList();
for (int i = 0; i < Integer.MAX_VALUE; i++) new Object();
So what ever you do, make sure you remove reference to object to no longer used (set reference to null or clear collection).
When the garbage collector will run is best left to JVM to decide. Well unless your program is about to start doing things that use a lot of memory and is speed critical so you may suggest JVM to run GC before going in as you may likely get the garbaged collected and extra memory to go on. Other wise, I personally see no reason to run System.gc().
Hope this helps.
Below is little summary I wrote back in the days (I stole it from some blog, but I can't remember where from - so no reference, sorry)
There is no manual way of doing garbage collection in Java.
Java Heap is divided into three generation for the sake of garbage collection. These are the young generation, tenured or old generation, and Perm area.
New objects are created in the young generation and subsequently moved to the old generation.
String pool is created in Perm area of Heap, Garbage collection can occur in perm space but depends on upon JVM to JVM.
Minor garbage collection is used to move an object from Eden space to Survivor 1 and Survivor 2 space, and Major collection is used to move an object from young to tenured generation.
Whenever Major garbage collection occurs application, threads stops during that period which will reduce application’s performance and throughput.
There are few performance improvements has been applied in garbage collection in Java 6 and we usually use JRE 1.6.20 for running our application.
JVM command line options -Xms and -Xmx is used to setup starting and max size for Java Heap. The ideal ratio of this parameter is either 1:1 or 1:1.5 based on my experience, for example, you can have either both –Xmx and –Xms as 1GB or –Xms 1.2 GB and 1.8 GB.
Command line options: -Xms:<min size> -Xmx:<max size>
Just to add to the discussion: Garbage Collection is not the only form of Memory Management in Java.
In the past, there have been efforts to avoid the GC in Java when implementing the memory management (see Real-time Specification for Java (RTSJ)). These efforts were mainly dedicated to real-time and embedded programming in Java for which GC was not suitable - due to performance overhead or GC-introduced latency.
The RTSJ characteristics
Immortal and Scoped Memory Management - see below for examples.
GC and Immortal/Scoped Memory can coexist withing one application
RTSJ requires a specially modified JVM.
RTSJ advantages:
low latency, no GC pauses
delivers predictable performance that is able to meet real-time system requirements
Why RTSJ failed/Did not make a big impact:
Scoped Memory concept is hard to program with, error-prone and difficult to learn.
Advance in Real-time GC algoritms reduced the GC pause-time in such way that Real-time GCs replaced the RTSJ in most of the real-time apps. However, Scoped Memories are still used in places where no latencies are tolerated.
Scoped Memory Code Example (take from An Example of Scoped Memory Usage):
import javax.realtime.*;
public class ScopedMemoryExample{
private LTMemory myMem;
public ScopedMemoryExample(int Size) {
// initialize memory
myMem = new LTMemory(1000, 5000);
}
public void periodicTask() {
while (true)) {
myMem.enter(new Runnable() {
public void run() {
// do some work in the SCOPED MEMORY
new Object();
...
// end of the enter() method, the scoped Memory is emptied.
}
});
}
}
}
Here, a ScopedMemory implementation called LTMemory is preallocated. Then a thread enters the scoped memory, allocates the temporary data that are needed only during the time of the computation. After the end of the computation, the thread leaves the scoped memory which immediately makes the whole content of the specific ScopedMemory to be emptied. No latency introduced, done in constant time e.g. predictable time, no GC is triggered.
From my experience, in java you should rely on the memory management that is provided by JVM itself.
The point I'd focus on in this topic is to configure it in a way acceptable for your use case. Maybe checking/understanding JVM tuning options would be useful: http://docs.oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm
You cannot avoid garbage collection if you use Java. Maybe there are some obscure JVM implementations that do, but I don't know of any.
A properly tuned JVM shouldn't require any System.gc() hints to operate smoothly. The exact tuning you would need depends heavily on what your application does, but in my experience, I always turn on the concurrent-mark-and-sweep option with the following flag: -XX:+UseConcMarkSweepGC. This flag allows the JVM to take advantage of the extra cores in your CPU to clean up dead memory on a background thread. It helps to drastically reduce the amount of time your program is forcefully paused when doing garbage collections.
Well, the GC is always there -- you can't create objects that are outside its grasp (unless you use native calls or allocate a direct byte buffer, but in the latter case you don't really have an object, just a bunch of bytes). That said, it's definitely possible to circumvent the GC by reusing objects. For instance, if you need a bunch of ArrayList objects, you could just create each one as you need it and let the GC handle memory management; or you could call list.clear() on each one after you finish with it, and put it onto some queue where somebody else can use it.
Standard best practices are to not do that sort of reuse unless you have good reason to (ie, you've profiled and seen that the allocations + GC are a problem, and that reusing objects fixes that problem). It leads to more complicated code, and if you get it wrong it can actually make the GC's job harder (because of how the GC tracks objects).
Basically the idea in Java is that you should not deal with memory except using "new" to allocate new objects and ensure that there is no references left to objects when you are done with them.
All the rest is deliberately left to the Java Runtime and is - also deliberately - defined as vaguely as possible to allow the JVM designers the most freedom in doing so efficiently.
To use an analogy: Your operating system manages named areas of harddisk space (called "files") for you. Including deleting and reusing areas you do not want to use any more. You do not circumvent that mechanism but leave it to the operating system
You should focus on writing clear, simple code and ensure that your objects are properly done with. This will give the JVM the best possible working conditions.
You are correct in saying that System.gc() is a request to the compiler and not a command. But using below program you can make sure it happens.
import java.lang.ref.WeakReference;
public class GCRun {
public static void main(String[] args) {
String str = new String("TEMP");
WeakReference<String> wr = new WeakReference<String>(str);
str = null;
String temp = wr.get();
System.out.println("temp -- " + temp);
while(wr.get() != null) {
System.gc();
}
}
}
I would suggest to take a look at the following tutorials and its contents
This is a four part tutorial series to know about the basics of garbage collection in Java:
Java Garbage Collection Introduction
How Java Garbage Collection Works?
Types of Java Garbage Collectors
Monitoring and Analyzing Java Garbage Collection
I found This tutorial very helpful.
"Nullify"ing the reference when not required is the best way to make an object eligible for Garbage collection.
There are 4 ways in which an object can be Garbage collected.
Point the reference to null, once it is no longer required.
String s = new String("Java");
Once this String is not required, you can point it to null.
s = null;
Hence, s will be eligible for Garbage collection.
Point one object to another, so that both reference points to same object and one of the object is eligible for GC.
String s1 = new String("Java");
String s2 = new String("C++");
In future if s2 also needs to pointed to s1 then;
s1 = s2;
Then the object having "Java" will be eligible for GC.
All the objects created within a method are eligible for GC once the method is completed. Hence, once the method is destroyed from the stack of the thread then the corresponding objects in that method will be destroyed.
Island of Isolation is another concept where the objects with internal links and no extrinsic link to reference is eligible for Garbage collection.
"Island of isolation" of Garbage Collection
Examples:
Below is a method of Camera class in android. See how the developer has pointed mCameraSource to null once it is not required. This is expert level code.
public void release() {
if (mCameraSource != null) {
mCameraSource.release();
mCameraSource = null;
}
}
How Garbage Collector works?
Garbage collection is performed by the daemon thread called Garbage Collector. When there is sufficient memory available that time this demon thread has low priority and it runs in background. But when JVM finds that the heap is full and JVM wants to reclaim some memory then it increases the priority of Garbage collector thread and calls Runtime.getRuntime.gc() method which searches for all the objects which are not having reference or null reference and destroys those objects.

If the object is referenced as then it is automatically frees the memory in j2me or not frees the memory in j2me?

Im a j2me developer. Now im developing a mobile application using j2me.
I had a doubt,
In java, If a create an object , then after some time we does not want it means,we make it null ,then it is automatically frees the memory and goes to garbage collection.
String str1=new String("Thamilan"); //Allocating a memory for str1
.......
......
str1=null; //Frees the memory of str1
The above code str1=null frees memory, My doubt is like that if we refer any object to null then it is goes to garbage collection (memory frees) in j2me is correct or not.
Please help me. The answer is very helpful to me. Because i had a problem of memory constraints in my mobile application.
Thanks & Regards
Yes, if all references to an object go away, it becomes eligible for garbage collection and the memory for it will eventually be freed. This will in general not happen immediately, but sometime later in a background thread or when the program threatens to run out of memory. This is true for J2ME as well.
What you should take care of in J2ME (even more so than in general) is to preserve memory at the allocating end, i.e. not create huge amounts of objects in the first place if it can be avoided.
PS:
String str1 = new String("Thamilan")
is better written as (and uses more memory than)
String str1 = "Thamilan";
String str1=new String("Thamilan"); //Allocating a memory for str1
.......
......
str1=null; //Frees the memory of str1
If all references go away, then memory will eventually be freed. But beware that writing this kind of code in stack (i.e. local variables, inside methods) offers no advantage at all; the compiler can infer if the variable can't be referenced after some point, so explicitly setting it to null has no effect whatsoever; the assignment will probably be optimized away immediately.
For heap (i.e. instance variables, inside classes) this kind of nulling may be useful, though. The compiler or the JVM has no way to know if someone is going to reference that variable in the future, possibly via reflection, so it must keep the object around unless its reference is null'd.
Better calling System.gc(); to call the garbage collection.

Categories