So let's say:
public class Sample { //main() class
public static void main(String[] args) {
A a = new A();
}
}
public class A {
A aa = new A();
}
So...when I run it ...it gives : java.lang.StackOverflowError.
So, my explanation is that object a generation at line 1, furthers creates object aa generation at line 2...and then it enters a recursion .... which keeps creating object after object, until the heap memory is full.
If the objects are created on Heap...then why does it say StackOverflowError ??
Well, it's using both heap and stack. The stack space is because you're in the constructor for A, recursively. It would be simpler to see this if you put the initialization in the body of the constructor:
public class A {
A aa;
public A() {
aa = new A();
}
}
So the A constructor calls itself, then calls itself, etc. There's generally rather more heap space available than stack space, hence why you're running out of stack space first. If your class had a lot of fields, you would conceivably run out of heap space first - although usually the heap is pretty huge in modern machines.
The reason for a stack overflow is simply that the stack runs out of space before the (small) As can fill up the heap.
You have correctly recognized the recursion. So!
Related
Trying to allocate (direct memory) with Javolution.Struct that contains arrays, and the memory "explodes". No idea why, Would love to have a clue
Class A holds array of 50 of class B. Class B holds array of 1 million unsigned shorts:
import javolution.io.Struct;
public class Test {
public static void main(String[] args) {
Test t = new Test();
t.work();
}
public void work() {
A a = new A();
System.out.println("a.size() = "+a.size()); // prints 100000000
}
}
public class A extends Struct {
public B[] randomName = array(new B[50]);
}
public class B extends Struct {
public Unsigned16[] someData = array(new Unsigned16[1000000]);
}
The reason I need those arrays in one piece is the comfort of calling getByteBuffer() and getting the whole structure as single piece of memory, directly allocated in non jvm memory
The memory shows (10 GB) 6 GB instead of 100MB
no clue why
[ javolution 6.1.0 ]
Edit 1:
A more concise issue found to cause the same memory problem:
public Unsigned16[] someData = array(new Unsigned16[50000000]);
Allocating 50m unsigned16 in main (class needs to extend Struct obv) function is expected to have a 100mb memory footprint where its actually allocates 6gb
Edit 2:
Its not happening if i'm calling the same line, without the wrapping with array() function:
public Unsigned16[] someData = new Unsigned16[50000000];
This is weird. I need the struct to contain this array, along with other Struct members (like Signed8 etc..), and when calling getByteBuffer() it will have the same piece of memory allocated and not pointers to different structs
Edit 3:
This works as expected:
ByteBuffer bb = ByteBuffer.allocateDirect(100*1000000); // allocates 100MB
I suspect there is a bug in Struct.array function in javolution lib. I will keep this post open until its fixed or someone post a workaround..
I have read my question one more time and I think the example was not good enought to show where was my confusion. So I will show a different example.
public class Main {
public static void main(String args[]) {
Foo foo = new Foo();
foo.deleteOtherFoo();
}
}
public class Foo {
private OtherFoo otherFoo;
public Foo() {
otherFoo = new OtherFoo();
}
public void deleteOtherFoo() {
this.otherFoo = null;
}
}
public class OtherFoo {
public OtherFoo() {}
}
If I follow what I know about stack and heap, I can say:
my draw
in the frame deleteOtherFoo what do I have as parameters? because I know I can only have primitive type or reference type value. In that case I have a reference type Foo.otherFoo ? a value that contain a pointer of a pointer ?
Because when I put this.otherFoo = null, I remove the ref of otherFoo from the object foo.
code lives in an entirely different place. Code is effectively unchanging, save some crazy 'reload this class from disk again please' shenanigans (which the JVM does support but that's an entirely different can of worms).
So where does 'the method' live? Well, nowhere. The CODE of the method lives in what used to be called permgen. It's definitely not the stack, never gets garbage collected, and no matter how many Foo objects you make, the code is located in memory only once.
And that's that.. until you call the method.
When you call the method, if it's non-static, it needs 'an instance'. This is, as far as the JVM is concerned, pretty much 100% the same as a parameter: If you call foo.doThingie(a);, then both foo and a are parameters to the doThingie method. These are put on the stack, and then doThingie is executed. Once doThingie finishes execution, the stack is reset to the point before doThingie was invoked, so, 'foo' and 'a' are now gone.
In java, all non-primitives are 'references' which is just javaspeak for 'pointers'. So when I say 'foo and a are on the stack', what I really mean is 'a pointer, into the heap, pointing at the data (i.e., the fields) that represent an instance of Foo, is on the stack'.
I know that object references are created on the stack, and the objects themselves are created on the heap. In the code below, I try to fill the heap by creating a large number of Main objects, using recursion in the constructor; However, instead of an OutOfMemoryError, I get a StackOverflowError
public class Main {
public Main() {
new Main();
}
public static void main(String[] args) {
new Main();
}
}
Why does this happen?
When you create an object with new, it invokes the object's constructor. The constructor is a method. Each method invocation results in the creation of another stack frame, each of which is using a portion of your available stack space. Once you run out of stack space, you will get a StackOverflowError. An unlimited recursion will quickly exhaust the available stack space. With your code, there is a race between which will exhaust first, stack space or heap space; however, with most default limits, the stack is going to be much smaller than the heap.
To cause an OutOfMemoryError create lots of objects inside a while(true) loop, and ensure that the objects aren't collectible by the garbage collector. For example:
public class MyObject {
int[] array = new int[1024*256];
static List<MyObject> myList = new LinkedList<>();
public static void main(String[] args) throws Exception {
while(true){
myList.add(new MyObject());
}
}
}
In the below program, does it mean that 3 instance variables and 3 instance methods are created and memory is allocated to them ?
class Foo{
String name = "";
public void greet(String name){
this.name = name;
}
}
class Greetings {
public static void main (String[] args) {
Foo ob = new Foo();
Foo ob1 = new Foo();
Foo ob2 = new Foo();
ob.greet("hello friends");
ob1.greet("welcome to java");
ob2.greet("let us learn");
System.out.println(ob.name);
System.out.println(ob1.name);
System.out.println(ob2.name);
}
}
The Java Language Specification does not say anything about how memory is organized, or how objects, methods, and classes are represented.
So, the answer is: you can't and shouldn't know.
All the 3 objects are stored in a heap memory. The size of the heap increases decreases as the application runs. The new operator here allocates memory to the object in the heap. Which means each time you say new in the statement a separate memory space is allocated to that object in the heap The methods are stored in JVM internal heap.
you can find a simple example of how memory is managed for objects in java here
Instance variables go on stack and objects go on heap and object references go on stack. Right? But what if an instance variable was a reference to an object? Like var c:
class clony implements Cloneable {
clony c = new clony();
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class tst2 {
public static void main(String[] args) throws CloneNotSupportedException {
clony j1 = new clony();
}
}
And if it goes on heap why it throws and stack overflow error?
Your reference c is a field of the class clony. That means the reference will be stored on the heap inside the memory region that is allocated for the clony object.
And your program throws a stack overflow exception since clony infinitely constructs itself: Inside the constructor of clony you create a new clony object and assign it to field c: Which will then do the same thing again and again.
This is because the stack is also used to keep track of method calls. Every time you call a method (the class's default constructor, in this case), certain information is added to the stack for that purpose. When you have infinite recursion (as you have with your constructor), that fills up the stack PDQ.
I think this:
clony c = new clony();
Gives you the exception.
new clony() also has clony c = new clony()
inside... and it goes to infinity.
By the way, classes should be named with capital letter at the beginning.