Q1. How does Java allocate stack and heap memory?
Q6. Can finalize method be overloaded?
Ans. Yes but only the following version is called by garbage collector:
protected void finalize() throws Throwable { };
Q7. Should I override finalize method?
Ans. Unlike C++ destructors, the finalize() method in Java is unpredictable, often dangerous and generally unnecessary. Use try and finally blocks while implementing finalize method. The finalize() method should only be used in rare instances as a safety net or to terminate non-critical native resources. If you do happen to call the finalize() method in some rare instances then remember to call the super.finalize() as shown below:
protected void finalize() throws Throwable {
try {
//finalize subclass state
}
finally {
super.finalize();
}
}
Q8. An object is resurrected by making other object refer to the dying object in finalize method. Will this object be ever garbage collected?
A remote object needing unreferenced notification must implement the java.rmi.server.Unreferenced interface. When those references no longer exist, the unreferenced method will be invoked.
Note: You should not use "SIGSEGV" for this, since JVM catches this signal and re-throws it as a NullPointerException in most places. So it is better to send a SIGBUS.
Ans. Each time an object is created in Java it goes into the area of memory known as heap. The primitive variables like int and double are allocated in the stack (i.e. Last In First Out queue), if they are local variables and in the heap if they are member variables (i.e. fields of a class). In Java methods and local variables are pushed into stack when a method is invoked and stack pointer is decremented when a method call is completed. In a multi-threaded application each thread will have its own stack but will share the same heap. This is why care should be taken in your code to avoid any concurrent access issues in the heap space. The stack is thread-safe because each thread will have its own stack.
Q2. Is there any possible memory leak in Java?
Therefore, in summary we can say that one should/must :-
Q3. Explain memory management in java.
Q2. Is there any possible memory leak in Java?
Ans. Memory leak is unused but referenced part of the memory. Though GC takes care of cleaning up your memory/heap, but if you have used some native objects and forgot to reclaim the memory explicitly because that's anyway not going to be taken care by the GC (which takes care of heap memory management only).
Similarly, using 'static' also can be one of the potential reasons for memory leaks in Java. 'static' can't straightway be blamed for causing memory leaks; but if programmer has not taken care of the setting the references to 'null' explicitly after using the static objects then they can definitely cause memory leaks. Since 'static' members will by default live for the entire life of an app unless they are explicitly set to 'null'. So, always make it a point to nullify the references as soon as you reach at a point in your code where the use of the static member is over.
Ex: Suppose you have created a 'Statement' object from a DB Connection and the connection is a pooled one. Now as you know calling close() method on a pooled connection will not actually close the connection instead it will return the Connection object to the pool to be re-used. So, in such a case unless you explicitly close the 'Statement' object, it would keep consuming precious memory space for no real use. Now if you have declared the 'Statement' object as a static member, it'll be maintained in the memory for the entire life time of the app even when the control is out of the scope. Now that if your Statement object is non-static, it will eligible for garbage collection, once it is out-of-scope. However, there is still wastage of memory after using the Statement last and before reaching the end of the local scope.
Therefore, in summary we can say that one should/must :-
- Always think if you really need to make this variable/member a 'static'.
- Always try to confine the scope of an object to restrict its usage only to the section it's actually needed.
- Always make a conscious effort to explicitly nullify objects once you finish using them (especially the large objects)
Q3. Explain memory management in java.
Ans. In java, memory is managed via garbage collector. Few techniques for memory management are:
1. Reference Counting: A count of references to each object is maintained. When garbage collector runs, it deletes objects with zero reference count.
Drawback: Circular references are maintained in memory.
2. Tracing collectors/Copy Collector/Stop and copy collector: Start from a root object and keep a track of all references which have direct/indirect reference to the root object. Then all the live objects are moved to another heap, taking care of references properly.
Drawback: At each point of time, you will have 2 heaps thus consuming twice the memory.
3. Mark sweep collectors/Stop and work collector: Similar to tracing collector except that instead of copying the references to the new heap, they are swept out of memory, after a list of live and dead objects is known.
Mark and sweep is a stop-the-world garbage collection technique; that is all application threads stop until garbage collection completes or until a higher-priority thread interrupts the garbage collector. If the garbage collector is interrupted it must restart which can lead to application thrashing with little apparent result.
Q4. Does Java have destructors?
Ans. Garbage collector does the job working in the background. Java does not have destructors; but it has finalizer that does a similar job. Syntax is
public void finalize() { }
If an object has a finalizer, the method is invoked before the system garbage collects the object.
Q5. Does the finalize method in subclass invoke finalize method in super class?
If an object has a finalizer, the method is invoked before the system garbage collects the object.
Q5. Does the finalize method in subclass invoke finalize method in super class?
Ans. Finalize is not implicitly chained. A finalize method in sub-class should call finalize in super class explicitly as its last action for proper functioning. Compilers don’t enforce this check.
Ans. Yes but only the following version is called by garbage collector:
protected void finalize() throws Throwable { };
Q7. Should I override finalize method?
Ans. Unlike C++ destructors, the finalize() method in Java is unpredictable, often dangerous and generally unnecessary. Use try and finally blocks while implementing finalize method. The finalize() method should only be used in rare instances as a safety net or to terminate non-critical native resources. If you do happen to call the finalize() method in some rare instances then remember to call the super.finalize() as shown below:
protected void finalize() throws Throwable {
try {
//finalize subclass state
}
finally {
super.finalize();
}
}
Q8. An object is resurrected by making other object refer to the dying object in finalize method. Will this object be ever garbage collected?
Ans. Resurrection can happen in finalize method which will prevent GC to reclaim the object memory. However this could be done only once. Next time GC will not invoke finalize method before garbage collection.
Well, the problem is that an object which overrides finalize() must now be determined to be garbage in at least two separate garbage collection cycles in order to be collected. When the first cycle determines that it is garbage, it becomes eligible for finalization. Because of the (slim, but unfortunately real) possibility that the object was "resurrected" during finalization, the garbage collector has to run again before the object can actually be removed. And because finalization might not have happened in a timely fashion, an arbitrary number of garbage collection cycles might have happened while the object was waiting for finalization. This can mean serious delays in actually cleaning up garbage objects, and is why you can get OutOfMemoryErrors even when most of the heap is garbage.
Q9. Explain types of references in Java? java.lang.ref package can be used to declare soft, weak and phantom references.
Strong Reference: By default.
Weak references: A weak reference is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself. You create a weak reference like this:
2. PhantomReferences avoid a fundamental problem with finalization – resurrection. With PhantomReference, resurrection is impossible. When a PhantomReference is enqueued, there is absolutely no way to get a pointer to the now-dead object.Arguably, the finalize() method should never have been provided in the first place. PhantomReferences are definitely safer and more efficient to use, and eliminating finalize() would have made parts of the VM considerably simpler. But, they're also more work to implement, so I confess to still using finalize() most of the time. The good news is that at least you have a choice.
Q10. Talk about garbage collector for various references.
Ans. If an element is determined to be eligible for processing, GC must determine if it is eligible for collection. The first criterion here is simple. Is the referent marked? If it is marked, the reference object is not eligible for collection and GC moves onto the next element of the list. However, if the referent is not marked and is eligible for collection, the process differs for each reference type.
Soft references are collected if their referent has not been marked for the previous 32 garbage collection cycles. You adjust the frequency of collection with the -Xsoftrefthreshold option. If there is a shortage of available storage, all soft references are cleared. All soft references are guaranteed to have been cleared before the OutOfMemoryError is thrown.
Weak and phantom references are always collected if their referent is not marked.
Q9. Explain types of references in Java? java.lang.ref package can be used to declare soft, weak and phantom references.
Ans. There are actually four different degrees of reference strength: strong, soft, weak, and phantom, in order from strongest to weakest:
Strong Reference: By default.
Weak references: A weak reference is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself. You create a weak reference like this:
WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
weakWidget.get() // get the actual Widget
Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that weakWidget.get() suddenly starts returning null.
weakWidget.get() // get the actual Widget
Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that weakWidget.get() suddenly starts returning null.
Soft references: A soft reference is exactly like a weak reference, except that it is less eager to throw away the object to which it refers. An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while. Soft References aren't required to behave any differently than WeakReferences, but in practice softly reachable objects are generally retained as long as memory is in plentiful supply. This makes them an excellent foundation for a cache, since you can let the garbage collector worry about both how reachable the objects are and how badly it needs the memory they are consuming.
Phantom references
A phantom reference is quite different than either SoftReference or WeakReference. Its grip on its object is so tenuous that you can't even retrieve the object -- its get() method always returns null. The only use for such a reference is keeping track of when it gets enqueued into a ReferenceQueue, as at that point you know the object to which it pointed is dead. How is that different from WeakReference, though?
The difference is in exactly when the enqueuing happens. WeakReferences are enqueued as soon as the object to which they point becomes weakly reachable. This is before finalization or garbage collection has actually happened. In case of Weak Reference, object could even be "resurrected" by an finalize() method, but the WeakReference would remain dead. PhantomReferences are enqueued only when the object is physically removed from memory, and the get() method always returns null specifically to prevent you from being able to "resurrect" an almost-dead object.
Use of Phantom Reference:
1. They allow you to determine exactly when an object was removed from memory. They are in fact the only way to determine that. This isn't generally that useful, but might come in handy in certain very specific circumstances like manipulating large images: if you know for sure that an image should be garbage collected, you can wait until it actually is before attempting to load the next image, and therefore make the dreaded OutOfMemoryError less likely.2. PhantomReferences avoid a fundamental problem with finalization – resurrection. With PhantomReference, resurrection is impossible. When a PhantomReference is enqueued, there is absolutely no way to get a pointer to the now-dead object.Arguably, the finalize() method should never have been provided in the first place. PhantomReferences are definitely safer and more efficient to use, and eliminating finalize() would have made parts of the VM considerably simpler. But, they're also more work to implement, so I confess to still using finalize() most of the time. The good news is that at least you have a choice.
Ans. If an element is determined to be eligible for processing, GC must determine if it is eligible for collection. The first criterion here is simple. Is the referent marked? If it is marked, the reference object is not eligible for collection and GC moves onto the next element of the list. However, if the referent is not marked and is eligible for collection, the process differs for each reference type.
Soft references are collected if their referent has not been marked for the previous 32 garbage collection cycles. You adjust the frequency of collection with the -Xsoftrefthreshold option. If there is a shortage of available storage, all soft references are cleared. All soft references are guaranteed to have been cleared before the OutOfMemoryError is thrown.
Weak and phantom references are always collected if their referent is not marked.
Soft
vs Weak vs Phantom References
|
||||
Type
|
Purpose
|
Use
|
When
GCed
|
Implementing
Class
|
Strong Reference |
An ordinary reference. Keeps
objects alive as long as they are referenced.
|
normal reference.
|
Any object not pointed to can be
reclaimed.
|
default
|
Soft Reference
|
Keeps objects alive provided
there’s enough memory.
|
to keep objects alive even after
clients have removed their references (memory-sensitive caches), in case
clients start asking for them again by key.
|
After a first gc pass, the JVM
decides it still needs to reclaim more space.
|
java.lang.ref.SoftReference
|
Weak Reference
|
Keeps objects alive only while
they’re in use (reachable) by clients.
|
Containers that automatically
delete objects no longer in use.
|
After gc determines the object is
only weakly reachable
|
java.lang.ref.WeakReference
java.util.WeakHashMap
|
Phantom Reference
|
Lets you clean up after
finalization but before the space is reclaimed (replaces or augments the use
of finalize())
|
Special clean up processing
|
After finalization.
|
java.lang.ref.PhantomReference
|
Q11. Explain garbage collection on Remote Objects or Distributed Garbage collection.
Ans. In a distributed system, just as in the local system, it is desirable to automatically delete those remote objects that are no longer referenced by any client. This frees the programmer from needing to keep track of the remote objects' clients so that it can terminate appropriately. RMI uses a reference-counting garbage collection algorithm for the same.
To accomplish reference-counting garbage collection, the RMI runtime keeps track of all live references within each Java virtual machine. When a live reference enters a Java virtual machine for first time, it sends a "referenced" message to the server for the object. Going forward, whenever a live reference enters JVM, its reference count is incremented and is decremented as soon as it leaves the JVM. When the last reference has been discarded, an unreferenced message is sent to the server. Many subtleties exist in the protocol; most of these are related to maintaining the ordering of referenced and unreferenced messages in order to ensure that the object is not prematurely collected.
When a remote object is not referenced by any client, the RMI runtime refers to it using a weak reference. The weak reference allows the Java virtual machine's garbage collector to discard the object if no other local references to the object exist. As long as a local reference to a remote object exists, it cannot be garbage-collected and it can be passed in remote calls or returned to clients. Remote objects are only collected when no more references, either local or remote, still exist. The distributed garbage collection algorithm interacts with the local Java virtual machine's garbage collector in the usual ways by holding normal or weak references to objects.
In addition to the reference counting mechanism, a live client reference has a lease with a specified time. When the client is done with the reference and allows the remote stub to go out of scope, or when the lease on the object expires, the reference layer on the host automatically deletes the record of the remote reference and notifies the client's reference layer that this remote reference has expired. The lease time is controlled by the system property java.rmi.dgc.leaseValue. The value is in milliseconds and defaults to 10 minutes. The concept of expirable leases, as opposed to strict on/off references, is used to deal with situations where a client-side failure or a network failure keeps the client from notifying the server that it is done with its reference to an object.
Q12. Does OutOfMemoryError and StackOverFlowError cause JVM crash?
Ans. Any problem in PURE Java code throws a Java exception or error. Java exceptions or errors will NOT cause a core dump (on UNIX systems) or a Dr.Watson error (on WIN32systems). Any serious Java problem will result in an OutOfMemoryError thrown by the JVM with the stack trace and consequently JVM will exit. An OutOfMemoryError (not jvm crash) can be thrown due to one of the following 4 reasons:
1. JVM may have a memory leak due to a bug in its internal heap management implementation. But this is highly unlikely because JVMs are well tested for this.
2. The application may not have enough heap memory allocated for its running. You can allocate more JVM heap size (with –Xmx parameter to the JVM) or decrease the amount of memory your application takes to overcome this. You can increase heap size as below:
java -Xms1024M -Xmx1024M
Care should be taken not to make the –Xmx value too large because it can slow down your application.
3. Another not so prevalent cause is the running out of a memory area called the “perm” which sits next to the heap. All the binary code of currently running classes is archived in the “perm” area. The ‘perm’ area is important if your application or any of the third party jar files you use dynamically generate classes.
For example: “perm” space is consumed when XSLT templates are dynamically compiled into classes, J2EE application servers, JasperReports, JAXB etc use Java reflection to dynamically generate classes and/or large amount of classes in your application. To increase perm space:
java -XX:PermSize=256M -XX:MaxPermSize=256M
java -XX:PermSize=256M -XX:MaxPermSize=256M
4. The fourth and the most common reason is that you may have a memory leak in your application.
Q13. Different OutOfMemory errors.
Q13. Different OutOfMemory errors.
Ans. Let’s have a look at the Sun HotSpot JVM and its concrete implementation of OutOfMemoryError errors.
1. In the heap we get an OutOfMemoryError, if the garbage collector cannot reclaim enough memory for a new object. In such situation the Sun HotSpot JVM shows this error message:
1. In the heap we get an OutOfMemoryError, if the garbage collector cannot reclaim enough memory for a new object. In such situation the Sun HotSpot JVM shows this error message:
java.lang.OutOfMemoryError: Java heap space
2. An alternative for this is as below, it occurs when application tries to create an array on the heap that is bigger than the total heap size.
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
3. If there is not enough memory in the method area for creating a new class, the Sun HotSpot implementation gets an error in the permanent generation:
java.lang.OutOfMemoryError: PermGen space
4. OutOfMemory errors in thread exclusive memory areas occur less frequently and are identified by the following error messages in the Sun HotSpot JVM:
java.lang.OutOfMemoryError: unable to create new native thread
This occurs if there are too many threads in the JVM and there is not enough memory left to create a new thread. I’ve seen this because the memory limits of a process have been reached (especially in 32bit operating systems, e.g. on Windows 32bit it is 2GB) or the maximum number of file handles for the user that executes the java process has been reached.
5. It indicates that a memory allocation error on a native stack (JNI method call) has occured.
java.lang.OutOfMemoryError: <reason> <stacktrace> (Native method)
6. It is also interesting that a memory allocation error on the JVM stack (too many frames on the stack) does not throw an Java OutOfMemory error but as the JVM specification mandates.
java.lang.StackOverflowError
7. The last variant of the OutOfMemoryError is out of swap space. This error is thrown if there is not enough memory left on the operating system level – which is normally true if other processes are using all of the available memory or the swap space is configured too small.
java.lang.OutOfMemoryError: request <size> bytes for <reason>.
Q14. Why does the JVM crash with a core dump or a Dr.Watson error?
Q14. Why does the JVM crash with a core dump or a Dr.Watson error?
Ans. Both the core dump on UNIX operating system and Dr.Watson error on WIN32 systems mean the same thing. If you define a crash as an unhandled problem (i.e. no Java Exception or Error); then this cannot be done from within Java. The JVM is a process like any other and when a process crashes a core dump is created. A core dump is a memory map of a running process. This can happen due to one of the following reasons:
1. Using JNI (Java Native Interface) code containing a fatal bug in it. Typical crashes in native code happen by dereferencing pointers to wrong memory areas (like Nullpointer) or illegal opcodes.
For ex: using Oracle OCI drivers, which are written partially in native code or JDBC-ODBC bridge drivers, which are written in non Java code. Using 100% pure Java drivers (communicates directly with the database instead of through client software utilizing the JNI) instead of native drivers can solve this problem.
2. The OS on which your JVM is running might require a patch or service pack.
3. The JVM implementation may have a bug in translating system resources like threads, file handles, sockets etc from the platform neutral Java byte code into platform specific operations. If this JVM’s translated native code performs an illegal operation then the operating system will instantly kill the process and mostly will generate a core dump file.
The core dump files are generated by the operating system in response to certain signals. The JVM can also intercept certain signals like SIGQUIT which is kill -3 <pid> from the operating system and it responds to this signal by printing out a Java stack trace and then continue to run. On the other hand signals like SIGSTOP (kill -23 <pid>) and SIGKILL (kill -9 <pid>) will cause the JVM process to stop or die. The JVM argument "java –Xsqnopause" will indicate JVM not to pause on SIGQUIT signal from OS.
4. On Linux/Unix, it is easy to crash JVM crash by sending it a Signal to the running process.
Note: You should not use "SIGSEGV" for this, since JVM catches this signal and re-throws it as a NullPointerException in most places. So it is better to send a SIGBUS.