So in a language like C, memory is separated into 5 different parts: OS Kernel, text segment, static memory, dynamic memory, and the stack. Something like this:
If we declared a static array in C, you had to specify it's size beforehand after that would be fixed forevermore. The program would allocate enough memory for the array and stick it in the static data segment as expected.
However I noticed that in Java, you could do something like this:
public class Test {
static int[] a = new int[1];
public static void main( String[] args ) {
a = new int[2];
}
}
and everything would work as you'd expect. My question is, why does this work in Java?
EDIT: So the consensus is that an int[] in Java is acts more similarly to an int* in C. So as a follow up question, is there any way to allocate arrays in static memory in Java (if no, why not)? Wouldn't this provide quicker access to such arrays?
EDIT2: ^ this is in a new question now: Where are static class variables stored in memory?
The value of a is just a reference to an object. The array creation expression (new int[2]) creates a new object of the right size, and assigns a reference to a.
Note that static in Java is fairly separate to static in C. In Java it just means "related to the type rather than to any particular instance of the type".
In java any time you use the word new, memory for that object is allocated on the heap and a reference is returned. This is also true for arrays. The int[] a is just the reference to new int[1]. When you do new int[2], a new array is allocated and pointed to a. The old array will be garbage collected when needed.
You are creating a new array, not modifying the old one. The new array will get its own space and the old one will be garbage-collected (so long as nobody else holds a reference to it).
I assume when you're referring to "static memory" you're referring to the heap. In Java, the heap serves a similar purpose to the "static data segment" you mentioned. The heap is where most objects are allocated, including arrays. The stack, on the other hand, is where objects that are used only during the life of a single method are placed.
In Java you've merely asked that a strongly typed reference to an array be stored statically for the class Test. You can change what a refers to at runtime, which includes changing the size. This would be the C equivalent of a static storage of an int*.
In Java, a static variable exists as part of the class object. Think of it as an instance variable for the class itself. In your example, a is a reference variable, which refers to some array (or no array at all, if it is null), but the array itself is allocated as all arrays are in Java: off the heap.
Static has a different meaning in Java. In Java when you declare a variable as static it is a class variable and not an instance variable.
Related
This is the usual way for declare a Java array:
int[] arr = new int[100];
But this array is using heap space. Is there a way we can declare an array using stack space like c++?
Arrays are objects irrespective of whether it holds primitive type or object type, so like any other object its allocated space on the heap.
But then from Java 6u23 version, Escape Analysis came into existence, which is by default activated in Java 7.
Escape Analysis is about the scope of the object, when an object is defined inside a method scope rather than a class scope, then the JVM knows that this object cant escape this limited method scope, and applies various optimization on it.. like Constant folding, etc
Then it can also allocate the object which is defined in the method scope,
on the Thread's Stack, which is accessing the method.
In a word, no.
The only variables that are stored on the stack are primitives and object references. In your example, the arr reference is stored on the stack, but it references data that is on the heap.
If you're asking this question coming from C++ because you want to be sure your memory is cleaned up, read about garbage collection. In short, Java automatically takes care of cleaning up memory in the heap as well as memory on the stack.
Arrays are dynamically allocated so they go on the heap.
I mean, what happens when you do this:
int[] arr = new int[4];
arr = new int[5];
If the first allocation was done on the stack, how would we garbage collect it? The reference arr is stored on the stack, but the actual array of data must be on the heap.
It's not yet supported as a language feature, because that would require value types since passing on-stack data by reference would not be safe.
But as an optimization (escape analysis) the JVM may already do that for local variables containing small, fixed-size arrays iff it can prove that it does not escape the local/callee scope. That said, it's just a runtime optimization and not some spec guarantee, so relying on it is difficult.
I want to know why an array created in Java static even when we use the new keyword to define it.
From what I've read, the new keyword allocates a memory space in the heap whenever it is encountered during run time, so why give the size of the array at all during definition.
e.g. Why can't
int[] array1=new int[20];
simply be:
int[] array1=new int[];
I know that it does not grow automatically and we have ArrayList for that but then what is the use of keyword new in this? It could have been defined as int array1[20]; like we used to do it in C, C++ if it has to be static.
P.S. I know this is an amateurish question but I am an amateur, I tried to Google but couldn't find anything comprehensive.
This may be an amateurish question, but it is one of the best amateurish questions you could make.
In order for java to allow you to declare arrays without new, it would have to support an additional kind of data type, which would behave like a primitive in the sense that it would not require allocation, but it would be very much unlike a primitive in the sense that it would be of variable size. That would have immensely complicated the compiler and the JVM.
The approach taken by java is to provide the bare minimum and sufficient primitives in order to be able to get most things done efficiently, and let everything else be done using objects. That's why arrays are objects.
Also, you might be a bit confused about the meaning of "static" here. In C, "static" means "of file scope", that is, not visible by other object files. In C++ and in Java, "static" means "belongs to the class" rather than "belongs to instances of the class". So, the term "static" is not suitable for describing array allocation. "Fixed size" or "fixed, predefined size" would be more suitable terms.
Well, in Java everything is an object, including arrays (they have length and other data). Thats why you cannot use
int var[20];
In java that would be an int and the compiler would be confused. Instead by using this:
int[] var;
You are declaring that var is of type int[] (int array) so Java understands it.
Also in java the length of the array and other data are saved on the array, for this reason you don't have to declare size of array during declaration, instead when creating an array (using new) the data are saved.
Maybe there is a better reason that oracle may have answered already, but the fact that in Java everything is an object must have something to do with it. Java is quite specific about objects and types, unlike C where you have more freedom but everything is more loose (especially using pointers).
The main idea of the array data structure is that all its elements are located in the sequential row of memory cells. That is why you can not create array with variable size: it should be unbounbed space vector in memory for this purpose, which is impossible.
If you want change size of array, you should recreate it.
Since arrays are fixed-size they need to know how much memory to allocate at the time they are instantiated.
ArrayLists or other resizing data structures that internally use arrays to store data actually re-allocate larger arrays when their inner array data
structure fills up.
My understanding of OP's reasoning is:
new is used for allocating dynamic objects (which can grow like, ArrayList), but arrays are static (can't grow). So one of them is unnecessary: the new or the size of the array.
If that is the question, then the answer is simple:
Well, in Java new is necessary for every Object allocation, because in Java all objects are dynamically allocated.
Turns out that in Java, arrays are objects, different from C/C++ where they are not.
All of Java's variables are at most a single 64bit field. Either primitives like
integer (32bit)
long (64bit)
...
or references to Objects which depending on JVM / config / OS are 64 or 32 bit fields (but unlike 64bit primitives with atomicity guaranteed).
There is no such thing as C's int[20] "type". Neither is there C's static.
What int[] array = new int[20] boils down to is roughly
int* array = malloc(20 * sizeof(java_int))
Each time you see new in Java you can imagine a malloc and a call to the constructor method in case it's a real Object (not just an array). Each Object is more or less just a struct of a few primitives and more pointers.
The result is a giant network of relatively small structs pointing to other things. And the garbage collector's task is to free all the leaves that have fallen off the network.
And this is also the reason why you can say Java is copy by value: both primitives and pointers are always copied.
regarding static in Java: there is conceptually a struct per class that represents the static context of a class. That's the place where static instance variables are anchored. Non-static instance variables are anchored at with their own instance-struct
class Car {
static int[] forAllCars = new int[20];
Object perCar;
}
...
new Car();
translates very loosely (my C is terrible) to
struct Car-Static {
Object* forAllCars;
};
struct Car-Instance {
Object* perCar;
};
// .. class load time. Happens once and this is referenced from some root object so it can't get garbage collected
struct Car-Static *car_class = (struct Car-Static*) malloc(sizeof(Car-Static));
car_class->forAllCars = malloc(20 * 4);
// .. for every new Car();
struct Car-Instance *new_reference = (struct Car-Instance*) malloc(sizeof(Car-Instance));
new_reference.perCar = NULL; // all things get 0'd
new_reference->constructor();
// "new" essentially returns the "new_reference" then
This is the usual way for declare a Java array:
int[] arr = new int[100];
But this array is using heap space. Is there a way we can declare an array using stack space like c++?
Arrays are objects irrespective of whether it holds primitive type or object type, so like any other object its allocated space on the heap.
But then from Java 6u23 version, Escape Analysis came into existence, which is by default activated in Java 7.
Escape Analysis is about the scope of the object, when an object is defined inside a method scope rather than a class scope, then the JVM knows that this object cant escape this limited method scope, and applies various optimization on it.. like Constant folding, etc
Then it can also allocate the object which is defined in the method scope,
on the Thread's Stack, which is accessing the method.
In a word, no.
The only variables that are stored on the stack are primitives and object references. In your example, the arr reference is stored on the stack, but it references data that is on the heap.
If you're asking this question coming from C++ because you want to be sure your memory is cleaned up, read about garbage collection. In short, Java automatically takes care of cleaning up memory in the heap as well as memory on the stack.
Arrays are dynamically allocated so they go on the heap.
I mean, what happens when you do this:
int[] arr = new int[4];
arr = new int[5];
If the first allocation was done on the stack, how would we garbage collect it? The reference arr is stored on the stack, but the actual array of data must be on the heap.
It's not yet supported as a language feature, because that would require value types since passing on-stack data by reference would not be safe.
But as an optimization (escape analysis) the JVM may already do that for local variables containing small, fixed-size arrays iff it can prove that it does not escape the local/callee scope. That said, it's just a runtime optimization and not some spec guarantee, so relying on it is difficult.
I'm writing an array-backed hashtable in Java, where the type of key and value are Object; no other guarantee.
The easiest way for me code-wise is to create an object to hold them:
public class Pair {
public Object key;
public Object value;
}
And then create an array
public Pair[] storage = new Pair[8];
But how does the jvm treat that in memory? Which is to say, will the array actually:
be an array of pointers to Pair() objects sitting elsewhere, or
contain the actual data?
edit
Since the objects are instantiated later as new Pair(), they're randomly placed in the heap. Is there any good way to ensure they're sequential in the heap? Would I need to do some trickery with sun.misc.unsafe to make that work?
Explaining my motivation, if I want to try and ensure that sequential items are in the same page of memory, is there any way to do this in Java?
The array will be an object on the heap containing pointers to the Pair objects which will also be on the heap (but separate from the array itself).
No, the storage array will only contain pointers to the actual Pair objects existing somewhere else on the heap. Yet, remember to instantiate 8 Pair objects and make each element of the array point to these objects. You need to have something like this after the code that you have written:
for(int i=0;i<storage.length;i++)
storage[i] = new Pair() ;
Only then will the Pair objects be created and correctly referred to by the storage array.
Programing languages like C,C++ will not store array values in Heap rather it keeps the value in STACK. But in Java why there is a necessity to keep array values in heap?
In Java, arrays (just like all other objects) are passed around by reference: When you pass an array to a method, it will get a reference pointing to the same location in memory, no copy is being made. This means that the array needs to remain "alive" after the method that created it, and so cannot be stored in the stack frame for the method. It needs to managed by the garbage collector, just like all other objects.
There is some research going in to optimize JVM memory allocation using "escape analysis": If an object (such as an array) can be guaranteed to never leave the current scope, it becomes possible to in fact allocate it on the stack, which is more efficient.
A short answer is that an array in Java is a reference type, and reference types live on the heap. It's worth noting that in C#, one can switch to unsafe mode and initialise arrays with stackalloc which will create the array on the stack. It's therefore quite probable that the VM would allow you to make an array on the stack, and it's merely an implementation detail that means arrays all live on the heap.
int[]a={10,20,30};
this array stores on stack, but the following array stores in heap:
`int[]num=new int num[2];`//here we build the object of array , object always located in heap
always treat arrays like java object, so do not be confused by the fact that arrays don't store on ram when we have a declaration like the one above.