I was expecting outOfMemory but here I get stackOverFlow in java - java

package com.atul;
public class StackOverFlow {
public StackOverFlow() {
callStackOverFlow();
}
public void callStackOverFlow() {
StackOverFlow st = new StackOverFlow();
}
public static void main(String[] args) {
StackOverFlow st2 = new StackOverFlow();
}
}
In above program I was trying to get OutOfMemory error but I get StackOverFlow error. As per my knowledge all the objects are created in the Heap. Here we are doing recursion with constructor, still I get the StackOverFlow error.
Why?

You run out of stack (which has a maximum depth around 10,000 for simple cases) long before you run out of heap memory. This is because every thread has its own stack so it must be a lot smaller than the shared heap.
If you want to run out of memory, you need to use up the heap faster.
public class OutOfMemoryMain {
byte[] bytes = new byte[100*1024*1024];
OutOfMemoryMain main = new OutOfMemoryMain();
public static void main(String... args) {
new OutOfMemoryMain();
}
}

The stack size in the JVM is limited (per-thread) and configurable via -Xss.
If you want to generate an OOM, I would suggest looping infinitely and instantiating a new object per loop, and storing it in a collection (otherwise the garbage collection will destory each instance)

Before the memory get full of objects and program aborts due to out of memory; you ran out of stack which stores the method call and hence you are getting Stackoverflow Error.
Overflow error would come when your objects would fill up the heap space...

Related

Does While true loop always cause Out of memory error?

I always thought that a while (true) {...Any code..} would always result in a out of memory error.
But as I go deeper in java it seems it might not be like that.
I'm not able to confirm but if we have a while true that only does calculations, We are not expected to have an out of memory error, only a very detrimental cpu performance, right?
On the other hand if we are always requiring more memory it is expected to have a out of memory error.
I've 3 cases below.
calculations only (I think no memory is being allocated under the hood)
Ever increasing arraylist which it looks an obvious out of memory error
always instanting arraylist with new keyword. I dont know if it causes an out of memory error, because of garbage collector.
I'm not testing im my pc because I only have one, hope someone has the knowledge.
Code
import java.util.*;
public class HelloLeak{
//calculations only, MemoryLeak?
public static void outofmemo1(){
long i = 0;
while (true)
{
i = i * i;
}
}
//adding infinite number of objects, memory leak confirmed.
public static void outofmemo2(){
int i = 0;
List<Integer> l = new ArrayList<>();
while (true)
{
l.add(i);
}
}
//Creating infinite number of ArrayList objects, will garbage collector clear the unused objects or we will get memory leak?
public static void outofmemo3(){
List<Integer> l = new ArrayList<>();
while (true)
{
l = new ArrayList<>();
}
}
public static void main(String []args){
outofmemo1();
//outofmemo2();
//outofmemo3();
}
}
Will do absolutly nothing except ending in an endless loop.
Will crash with an OutOfMemoryError, because you add always a new element to the list, until the heap is filled.
Will be like 1. but you may have spikes up to for example 2GB, then the GC will come, see that there are unused objects, removes them. After that it will spike again, and so on

Android: Can a memory leak happen on the same thread?

I am new to handling the memory leak situations, but one thing that I have noticed is that all the examples showing memory leaks have the activity contexts on a different thread.
So I need to know if a memory leak can happen if there is an object reference on the same thread as well, because the activity reference is stored somewhere in other classes.
Thanks in advance!
A Memory Leak is a situation when there are objects present in the heap that are no longer used, but the garbage collector is unable to remove them from memory and, thus they are unnecessarily maintained.
Memory leaks can happend in the same thread as well. For example if a method stored data in a static variable which it does need to refer in the subsequent call.
E.g: In the code below we are storing numbers generates in a static list even though we do not require those generated numbers in subsequent calls.
public class MemoryLeak{
public static List<Double> list = new ArrayList<>();
public void doSomething() {
for (int i = 0; i < 10000000; i++) {
list.add(Math.random());
}
Log.info("Debug Point 2");
}
public static void main(String[] args) {
Log.info("Debug Point 1");
new MemoryLeak().doSomething();
Log.info("Debug Point 3");
}
}

SoftReference is not getting cleared by Java GC

I was trying to understand SoftReferences in Java which basically ensures clearing memories of SoftReferenced objects before throwing StackOverflowError.
public class Temp
{
public static void main(String args[])
{
Temp temp2 = new Temp();
SoftReference<Temp> sr=new SoftReference<Temp>(temp2);
temp2=null;
Temp temp=new Temp();
temp.infinite(sr);
}
public void infinite(SoftReference sr)
{
try
{
infinite(sr);
}
catch(StackOverflowError ex)
{
System.out.println(sr.get());
System.out.println(sr.isEnqueued());
}
}
}
However the outcome of above was
test.Temp#7852e922
false
Can someone explain me why the object was not cleared by GC? How can I make it work?
Looks like you may have some confusion with the StackOverFlowError and OutOfMemoryError. StackOverFlowError and OutOfMemoryError error are different. StackOverFlowError happens when there is no space in the call stack: OutOfMemoryError occurs when the JVM is unable to allocate memory in the heap space for a new object. Your code leads to StackOverflow: that means stack memory is full, not the heap space. I believe there will be enough space to store your SoftReference that's why it does not GCd the object.

Program gives error when for loop is commented

I have found a strange behaviour in my java program here is my code looks like this
public class JavaTest {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
public void test() {
{
System.out.println(dataSize);
byte[] data = new byte[dataSize];
}
// for (int i = 0; i < 10; i++) {
// System.out.println("Please be so kind and release memory");
// }
System.out.println(dataSize);
byte[] data2 = new byte[dataSize];
}
public static void main(String[] args) {
JavaTest jmp = new JavaTest();
jmp.test();
}
}
Here when I am commenting the for loop I am getting Exception in thread "main" java.lang.OutOfMemoryError: Java heap space that i can understand the jvm heap sapce is full.
But with that for loop in my code, it executes properly. How comes?
I think it's because you declare byte[] data inside { } block, which means data's scope ends when the code block ends. With loop uncommented, you are probably giving time to garbage collector to free the memory taken by data. And when you comment out the loop, GC doesn't have time to free up that memory yet.
If you remove { } around data declaration, it will also throw OutOfMemoryException even with loop uncommented.
UPDATE
This blog post stated in the comments by #SubOptimal proves this theory wrong, looks like it doesn't have anything to do with time needed by GC to free the memory. I'll quote relevant parts from the blog
The majority of responses were incorrect and suggested that the for() loop either gave the GC time to do its work during the System.out.println()...
Some of my readers realised that it had nothing to do with the System.out.println and that a simple int i = 0; would suffice. If you declare any local variable immediately after the code block, you break the strong reference to the byte[] held in the stack frame 1 before you invoke the new byte[] the second time.

How to derive the count of highest recursion level a recursive function will support?

How to derive the count of recursion level a recursive function will support without actually executing the function with different complex inputs. For e.g. when I execute below code it displays a level of recursion when the function throws stack overflow error. When I execute the program it displays "Recursion Terminated at 8373".
public class Application {
public static void main(String[] args) throws Exception {
RecursiveExperimenter experimenter = new RecursiveExperimenter();
experimenter.experiment();
}
}
class RecursiveExperimenter {
public void experiment() {
try {
A();
} catch (StackOverflowError e) {
System.out.println("Recursion Terminated at " + counter);
}
}
private void A() {
counter++;
int a = 0, b = 0, c = 0, d = 0;
A();
}
private int counter = 0;
}
How could I have derived that number without actually executing the function but by applying some mathematics? For this questions assume the stack size of the thread to be 1 MB. I am not clear about the overhead of the stack frame itself.
Thanks.
The answer is that this question has no specific answer.
There is no such thing as "the count of recursion level a recursive function will support". Nothing inherent in the concept of recursion imposes any limit on the level of recursion "supported".
In practice, the level of recursion you can achieve depends on the total stack memory available and how much memory each invocation takes up. This will in turn depend on the physical memory limits of the machine, the amount allocated to the JVM, the implementation of the JVM, whether or not the code has been optimized, and probably several other factors. It's even possible for heap memory to be the limiting factor if each invocation allocates large objects on the heap.
In other words, the achievable recursion level for a specific program is 100% dependent on the environment in which the code is run.

Categories