-1

I have the following code..

import java.util.Scanner;
import java.lang.Thread;
class Hello{  
public static void main(String[] args){  
try{
    long count =0;
 for(;;){
     A a = new A();
     count++;

     if(count%100 ==0)
     System.out.println("Created "+ count);

 }
}
catch(Exception ex){
    System.out.println("Exception occured");
    System.out.println(ex);
}}
}

class A{
int a = 10;
String str = generateRandom();
String str1 = generateRandom();
String str2 = generateRandom();
String str3 = generateRandom();
String str4 = generateRandom();
String str5 = generateRandom();
String str6 = generateRandom();
String str7 = generateRandom();
String str8 = generateRandom();
String str9 = generateRandom();
String str10 = generateRandom();
String rst1 = generateRandom();
String rst2 = generateRandom();
String rst3 = generateRandom();
String rst4 = generateRandom();
String rst5 = generateRandom();
String rst6 = generateRandom();
String rst7 = generateRandom();
String rst8 = generateRandom();
String rst9 = generateRandom();
String rst10 = generateRandom();



private static String generateRandom() {
    String aToZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random rand=new Random();
StringBuilder res=new StringBuilder();
for (int i = 0; i < 17; i++) {
   int randIndex=rand.nextInt(aToZ.length()); 
   res.append(aToZ.charAt(randIndex));            
}
return res.toString();

}

And I am running the java application with the following command..

java -Xmx100M Hello

I expect it to throw an Memory exception after a while, but the program runs consuming almost 100% CPU without crashing and occupying only 80.66MB almost constantly.

I am aware that the -Xmx set only heap size but not the other program related size.

If we set the -Xmx, will the application run in a degraded mode occupying only the limited heap size by running GC frequently ?

trincot
  • 317,000
  • 35
  • 244
  • 286
Shrikey
  • 858
  • 3
  • 11
  • 34
  • Did you try with a higher max heap size ? – Arnaud Apr 24 '18 at 06:28
  • there is nothing in the code that increase heap size. you create an instance of A, but it is removed after next loop iteration. Even you dont delete it, your strings are static. that means, every instance of A shares same memory block for its string – Adem Apr 24 '18 at 06:30
  • I wanted it to throw an exception. And yes i tried with 200MB as the max heap size where the program occupies around 140MB... – Shrikey Apr 24 '18 at 06:30
  • @Adem ... Realized that after posting.. Edited to generate the random strings.. – Shrikey Apr 24 '18 at 06:31
  • it is better. I would put an instance of A inside A, and set it with previous one. looks like a linked list. with that, you will not lose them from heap. like , A a = new A() , in top of loop , then inside loop. a.next = new A(); a = a.next; – Adem Apr 24 '18 at 06:33
  • Adding the items to the ArrayList threw an exception. I was under the impression that simply creating the objects in infinite for loop will cause the heap exception. Never expected GC to run in sync with the infinite loop and run the program in "DEGRADED" mode.. Thanks for the answers.. Don't understand why the question has to be downvoted.. – Shrikey Apr 24 '18 at 07:19
  • The GC doesn’t run “in sync with the infinite loop”. But an attempt to allocate an object when there is no available heap space will trigger a garbage collection. – Holger Apr 24 '18 at 07:43
  • Not sure what you mean by "degraded mode", it's not a concept that exists in the Java world. Note that your object may not even hit the real heap at all; HotSpot's escape analysis may detect no reference is ever given out for the object, so that it can allocate it on the stack. – Erwin Bolwidt Apr 24 '18 at 07:47
  • @ErwinBolwidt HotSpot never allocates objects on the stack (that would require RAM as well). If Escape Analysis proves that this is a local object, it may get dissolved into its fields, to get optimized like local variables, which in this case would imply there would be no remaining variables at all, as none of them are actually used (which would also imply the elimination of the `generateRandom()` invocations and their allocations). – Holger Apr 24 '18 at 09:42
  • @Holger Can you provide a link to back that up? A good description of stack allocation of objects can be found in the answer to this question: https://stackoverflow.com/questions/43002528/when-can-hotspot-allocate-objects-on-the-stack (Note, I'm not saying that HotSpot does it in the code above - I don't have time to check - but it could. And it would only need ram for 1 object instance because it knows when the object goes out of scope - at the next iteration of the for loop. But not sure if the current HotSpot implementation's ecape analysis is smart enough.) – Erwin Bolwidt Apr 24 '18 at 09:50
  • @Holger... also called scaler replacement – Eugene Apr 24 '18 at 10:23
  • @ErwinBolwidt you just provided the link yourself. Look at the answer you’ve linked and note the part “*Another important thing to know is that Hotspot does not actually implement stack allocation of objects. Instead it implements scalar replacement,*”, followed by a description similar to mine. – Holger Apr 24 '18 at 15:06

4 Answers4

2

You are not keeping more than one A object so the amount of memory required doesn't grow.

for(;;) {
    A a = new A();

} // doesn't need `a` any more.

A simple solution is to retain every object ever.

public class Main {
    public static void main(String... args) {

        int count = 0;
        try {
            List<Object> as = new ArrayList<>();
            for (; ; ) {
                as.add(new Object());
                count++;
                if (count % 1000000 == 0)
                    System.out.println(count);
            }
        } catch (OutOfMemoryError e) {
            System.out.println("Created " + count + " objects");
        }
    }
}

I suggest running this with -Xmx1g -Xms1g -verbose:gc

Note: as the program will try to keep running by cleaning up before it dies, it might take a long time to give up. i.e. the time to GC increases with the size of memory and is more often as you start to run low.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

Yes. If you set the -Xmx, the application will run in a degraded mode by occupying only the limited heap size and Your GC continuously performing garbage collection as you are not caching the object. Just try below code to get your expected exception.

import java.util.Scanner;
import java.lang.Thread;
import java.util.Random;
import java.util.ArrayList;

class Hello{  

    public static void main(String[] args){  
        try{
            long count =0;
            ArrayList<A> x = new ArrayList<A>();

         for(;;){
             A a = new A();
             x.add(a);
             count++;

             if(count%100 ==0)
             System.out.println("Created "+ count);

         }
        }
        catch(Exception ex){
            System.out.println("Exception occured");
            System.out.println(ex);
        }
    }
}


class A{
    int a = 10;
    String str = generateRandom();
    String str1 = generateRandom();
    String str2 = generateRandom();
    String str3 = generateRandom();
    String str4 = generateRandom();
    String str5 = generateRandom();
    String str6 = generateRandom();
    String str7 = generateRandom();
    String str8 = generateRandom();
    String str9 = generateRandom();
    String str10 = generateRandom();
    String rst1 = generateRandom();
    String rst2 = generateRandom();
    String rst3 = generateRandom();
    String rst4 = generateRandom();
    String rst5 = generateRandom();
    String rst6 = generateRandom();
    String rst7 = generateRandom();
    String rst8 = generateRandom();
    String rst9 = generateRandom();
    String rst10 = generateRandom();



    private static String generateRandom() {
        String aToZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random rand = new Random();
        StringBuilder res=new StringBuilder();
        for (int i = 0; i < 17; i++) {
           int randIndex=rand.nextInt(aToZ.length()); 
           res.append(aToZ.charAt(randIndex));            
        }
        return res.toString();
    }
}
S. M. Mohiuddin
  • 378
  • 3
  • 10
0

Your GC is removing the objects since you are not caching them, try to cache them is a List instead of creating a new object each time and assigning to the local variable, this supposes to throw the exception.

public static void main(String[] args){
    try {
        long count = 0;
        List<A> list = new ArrayList<A>();
        for (;;) {
            list.add(new A());
            count++;

            if (count % 100 == 0) {
                System.out.println("Created " + count);
            }

        }
    } catch (Exception ex) {
        System.out.println("Exception occured");
        System.out.println(ex);
    }
}

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.lang.Long.toString(Long.java:399) at java.lang.String.valueOf(String.java:3113) at javaapplication3.JavaApplication3.main(JavaApplication3.java:34) C:\Users\Ayat Abu Khadrah\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1enter code here BUILD FAILED (total time: 5 minutes 5 seconds)

Akhadra
  • 419
  • 3
  • 10
0

If you don't want to play with List, you can use

public static void main(String[] args){
    try {
        long count = 0;
        A current = new A();
        for (;;) {
            current.next = new A();
            current = current.next;
            count++;
            if (count % 100 == 0) {
                System.out.println("Created " + count);
            }
        }
    } catch (Exception ex) {
        System.out.println("Exception occured");
        System.out.println(ex);
    }
}
class A {
A next;
.
.
}
Adem
  • 9,402
  • 9
  • 43
  • 58