Does While true loop always cause Out of memory error? - java

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

Related

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.

I was expecting outOfMemory but here I get stackOverFlow in 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...

Java OutOfMemoryError not throwing

I was trying to study different exceptions in Java and came across the OutOfMemoryError and I wanted to see it in work so I wrote the following program to create infinite objects by creating them in a infinite loop. The program does go in infinite loop it does not throw the OutOfMemoryError exception.
class Test {
public static void main(String...args) {
while(true) {
Integer i = new Integer();
}
}
}
You are on the right track. The only thing you are missing is the concept of garbage collection. The program does infact create infinite Integer objects but after the 1st iteration, the object created in the previous iteration becomes eligible for GC.
Consider this:
Integer i;
i = new Integer(); // 1. create new object and make reference variable i refer to it.
i = new Integer(); // 2. create another object and make reference variable i refer to it...there is no way to get to the object created in step1 so obj in step 1 is eligible for GC.
If you want to see the OutOfMemoryError you need to somhow make sure that there is a way to get to the objects created in the infinite loop. So you can do something like:
class Test {
public static void main(String...args) {
Vector v = new Vector(); // create a new vector.
while(true) {
v.addElement(new Integer(1)); // create a new Integer and add it to vector.
}
}
}
In this program Integer objects are created infinitely as before but now I add them to a vector so ensure that there is a way to get to them and they do not become GC eligible.
Your variable i is garbage collected before you hit the OutOfMemoryError, since it isn't used anymore.
The easiest way to get an OutOfMemoryException is to create an array which doesn't fit into memory:
public class TestOutOfMemoryException
{
public static void main(String[] args)
{
final long maxMemory = Runtime.getRuntime().maxMemory();
System.out.println(maxMemory);
final byte[] boom = new byte[(int) maxMemory];
}
}
The variable i is only scoped to the loop, it doesn't survive past each iteration. Thus it is being garbage collected before the program can run out of memory. Try creating an ArrayList before entering the loop and adding each instance of i to it:
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
while (true) {
Integer i = new Integer();
list.add(i);
}
}
}
try with something like a
List l = new ArrayList();
int i = 0;
while(true) { l.add(i++); }

Categories