How Java and C manage memory of local variable? - java

I'm considering about how Java and C manage variable in a scope.
In java, every iterator, I create a new object and then print it. The result say that each iterator I have a new Object.
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
while (true) {
Ideone object = new Ideone();
System.out.println(object);
}
}
}
And variable of scope in C. I do the same as I do in Java. Every iterator I create a variable and print its address. But the result make me confusing because it's returning the same address, because I think every iterator it create a new variable at a random address
#include <stdio.h>
int main() {
while (1) {
int variable;
printf("%p\n", &variable);
}
}
Can anyone tell me what's under the hood of Java and C ?? And why C do not create a random address for it's variable ?
EDIT 1:
I have another question about dynamic memory management in C like this:
#include <stdio.h>
int main() {
while (1) {
int *variable = malloc(sizeof(int));
printf("%p\n", variable);
}
}
In this case, they print different address after each iterator. And each address is more then the previous the constant size.
But if free the memory like this, now it print the same address
#include <stdio.h>
int main() {
while (1) {
int *variable = malloc(sizeof(int));
printf("%p\n", variable);
realloc(variable, 0);
}
}
Is C memory management do not generate random address for new variable ?

In Java, the new Ideone() objects lifetime is not bound to a scope, you could return it from a function.
In your C code, int variable; creates an object that is automatically destroyed when you reach the end of the scope it was defined in.
Many implementations of C use a stack to allocate such objects. A stack will always give you the same address when used this way.
This comparision is a bit like apple vs. oranges. Comparing Java's new to C's malloc would show a similar behavior.

You're comparing apples to kumquats here - you're printing out the value of object (which is the address of something explicitly created on the heap each time through the loop) vs. the address of variable (which is an auto object that's typically allocated from the runtime stack).
variable has auto storage duration, meaning that storage for it is only guaranteed to be allocated over the lifetime of its enclosing scope (i.e., the body of the loop). However, as a matter of practice, most C compilers will allocate space for all auto variables in a function at function entry, even if the scope of those variables is limited to a smaller block within the function. IOW, the space for variable is allocated once, so its address doesn't change from iteration to iteration. And, given how most C implementations manage auto objects, it would be allocated from the same address anyway if it were allocated and deallocated with each loop iteration.
A more direct comparison would be looking at the address of the object variable itself, not its value, but I'm not sure how you would obtain that information (been a long time since I've done any Java).

In your Java code, you explicitly create a new object with every run in the loop. Thus, it is very likely that the different objects yield different memory addresses.
In you C-code, in contrast, you do not "create" anything, because variables are actually not "created". They are concepts of the programming language, and the compiler may decide when, where, and how often it reserves memory for the variable to hold a value. In practice, local variables are placed on the stack once at the beginning of a function or a loop, so it seems as if it were "created" only once, but this is actually something you cannot rely on.
Note, however, that the situation becomes a different one if you allocate "objects" in C as well. This would be rather comparable then to what Java does (in Java, all class-based types are handled through a pointer, but this isn't exposed to the user):
#include <stdio.h>
int main() {
while (1) {
int *variable = malloc(sizeof(int));
printf("%p\n", variable);
}
}
Besides memory leaks and running out of memory, this will print different memory addresses with each iteration.

Java use virtuel machine JVM. The garbage collection delete the variables when it's not needed any more.
In C the variables are stored in the stack or heap which you need you use malloc to allocate memory and free to deallocate.
Your output shows the address of variable in hexadecimal where in memory it's located and it's compilers decision in which memory address it should be stored.
local variables are put on the stack since in your code you did not used malloc to allocate memory on the heapit will give you the same address because stack is Last-in-first-out and your loop PUSH and POP in the same address, but if you close your terminal and run it again it will give you different address.
Close terminal and reopen run again it gives different address.

Related

When is Java variable created in memory?

I am wondering when is Java creating variables during runtime (when a function is called). Please see the examples below and answer whether those are one the same.
void function someFunction(boolean test) {
if (!test) {
return;
}
int[] myVar = new int[1000000];
...
}
void function someFunction(boolean test) {
int[] myVar = new int[1000000];
if (!test) {
return;
}
...
}
I wouldn't like so spend time allocating memory only for it to be deallocated moments later, so I need to know whether Java will allocate memory needed for a certain variable (or array) needed by a function at the very beginning of that function, regardless of where the declaration happened, or will it allocate memory when it reaches the point of declaration.
EDIT:
I'm terribly sorry for confusion I'm causing. When I say variable I mean object.
Probably at the point of method entry. It is a common compiler optimization to allocate a stack frame large enough to contain all locals. If that's so, it's pretty much a single subtraction to allocate space for them all. But you'd have to examine the bytecode to be sure.
However, in this:
int[] myVar = new int[1000000];
the 'variable' is a single reference, taking up 4 or 8 bytes. The object to which the variable refers is allocated at the point the initialization is encountered in execution, by the execution of the 'new' operator.
I suspect you need to read up on the distinction between variables and objects.
In general, the Java compiler is a bit dumb in its compilation since it leaves the optimization up to the runtime JVM. As such, the compilation is mostly a straightforward translation of source code into bytecode.
https://godbolt.org/z/5xT3KchrW
In this case with the OpenJDK 17.0.0 compiler, the allocation of the array is done roughly at the same point in the bytecode as where the source code indicates.
However, the local variable of the pointer to the array is "allocated" at the time the method is called via registers. While the JVM uses a stack frame in a way very similar to C/C++, on Android's Dalvik they instead use registers to hold local variables so it isn't ever actually "allocated" at all in memory (a design decision due to the focus on ARM -- with it's plentiful registers -- rather than x86 -- which is infamous for its lack of registers.

What happens to memory when stack is popped?

I have a function
public void f() {
int x = 72;
return;
}
So x is stored at possibly the address 0x9FFF.
When the function returns, what happens to the memory at that address? Is it still there? I.e is the value still 72? Or is it completely invalidated?
In C it is undefined behaviour.
In practice, if you were to try something like:
int *ptr;
void foo() {
bar();
printf("%d", *ptr);
}
void bar() {
int x = 72;
ptr = &x;
}
Then it's likely that in most implementations of C, foo() would print 72. This is because although the address referenced by ptr is available for reallocation, it's not likely to have been re-allocated yet, and nothing has overwritten that memory. The longer your program continues to run, initialising more local variables, and calling malloc(), the more likely it is that this memory address will be re-used, and the value will change.
However there's nothing in the C specification that says this must be the case - an implementation could zero that address as soon as it goes out of scope, or make the runtime panic when you try to read it, or, well, anything -- that's what "undefined" means.
As a programmer you should take care to avoid doing this. A lot of the time the bugs it would cause would be glaring, but some of the time you'll cause intermittent bugs, which are they hardest kind to track down.
In Java, while it's possible that the memory still contains 72 after it goes out of scope, there is literally no way to access it, so it does not affect the programmer. The only way it could be accessed in Java would be if there were an "official" reference to it, in which case it would not be marked for garbage collection, and isn't really out of scope.
Both the Java programming language and the Java virtual machine do not define what happens to the memory of a stack frame after the frame is popped. This is a low-level implementation detail that is masked by the higher level abstractions. In fact, the Java language and JVM bytecode make it impossible by design to retrieve already-deleted values from the stack (unlike C/C++).
In practice however, stack frames in Java will behave like stack frames in C. Growing the stack will bump its pointer (usually downward) and allocate space to store variables. Shrinking the stack will usually bump the pointer up and simply leave the old values in memory to rot without overwriting them. If you have low-level access to the JVM's stack memory region, this is the behavior you should expect to see.
Note that it is impossible in Java to do a trick like C where you attempt to read uninitialized stack variables:
static boolean firstTime = true;
public void f() {
int x;
if (firstTime) {
x = 72;
firstTime = false;
} else {
// Compile error: Variable 'x' may not have been initialized
System.out.println(x);
}
}
Other stack behaviors are possible in JVM implementations. For example, as frames are popped it is possible to unmap the 4 KiB virtual memory pages back to the operating system, which will actually erase the old values. Also on machine architectures such as the Mill, stack memory is treated specially so that growing the stack will always return a region filled with zero bytes, which saves the work of actually loading old values from memory.
Primitive types in Java are placed on the stack (into a local variables array of a frame). A new frame is created each time a method is invoked:
public void foo() {
int x = 72; // 'x' will be stored in the array of local variables of the frame
}
A frame is destroyed when its method invocation completes. At this moment all local variables and partial results might still reside on the stack, but they are abandoned and no longer available.
I'm not looking at the spec offhand, but I'm guessing that this isn't technically defined.
I actually tried something like that in C++ once and it was, in fact, 72 (or whatever I put there before the function call returned) if I remember correctly, so the machine didn't actually go through and write 0 to that location or something.
Some of this is an implementation detail, too. I implemented it in MIPS assembly language as well (I'll include a code sample if I can dig it up). Basically, when I needed registers, I'd just "grow" the stack by however many local variables I needed, store whatever the current values in the registers I needed were (so I could restore them later), and re-use the register. If that's the implementation, then the value could actually contain the value of a local variable in the caller. I don't think that that's exactly what Java's doing, though.
TL;DR It's an implementation detail, but in C at least odds are it won't overwrite the value in memory until it actually needs it. Java is much harder to predict.

When is memory space allocated to a variable?

Does the compiler allocate 4 bytes of memory when the variable is declared:
int a;
Or does it allocate memory when a value is assigned to it:
a = 5;
When is memory allocated? During variable declaration or initialization?
The variable is allocated when the structure containing it is allocated.
For a local variable in a method this is (with some caveats) when the method is invoked.
For a static variable this is when the class is "initialized" (which happens some time after it's loaded and before it's first used).
For an instance variable this is when the instance is created.
In most programming languages the compiler is allowed to choose when to allocate space for variables. The only thing you are guaranteed, is that the storage will be available if and when you need it.
A short anecdote...
The C programming language used to require that all variables used in a method be declared at the top of the method. This was because compilers used to reserve storage for all stack (local) variables in a method as soon as you entered the method. Today that requirement doesn't exist in part because compilers are a lot smarter.
Most compilers of C-like languages will defer allocation of instances until first use for optimized code. The REALLY tricky thing here is that the first use may not be where you think it is, and it may not occur at all. For example, if you have the following code:
int foo(int x) {
int y = 5;
if (x > 5)
y += x;
return y;
}
You might think the first use is when you assign 5 to y, but the compiler could optimize that code to something more like:
int foo(int x) {
if (x > 5)
return 5 + x;
return 5;
}
In this code y never really exists at all.
TL;DR - The compiler actually isn't guaranteed to allocate memory on declaration or use. Trust the compiler, it is (usually) smarter than us all.
When we have “declared'' a variable, we have meant that we have told the compiler about the variable; i.e. its type and its name, as well as allocated a memory cell for the variable (either locally or globally). This latter action of the compiler, allocation of storage, is more properly called the definition of the variable.
Simply Definition = Variable Declaration + Variable initialization
JVM divides memory into stack and heap memory. Whenever we declare new variables and objects, call new method, declare a String or perform similar operations, JVM designates memory to these operations from either Stack Memory or Heap Space.
Local variables are created in the stack
Instance variables are created in the heap & are part of the object they belong to.
Reference variables are created in the stack.

what actually compiler does when we declare variable?

let have an example.
public class test {
public static void main(String args[]) {
int a=5,b=4;
int c=a+b;
int d=9;
System.out.println("ANSWER PLEASE..");
}
}
Now when we execute this code what os does?
It first create a variable named a and alocates a memory address similar things for b and c.
now what happen to d. os creates a new memory address or it just reffer to the address of c as the value is same.
First of all, the compiler doesn't do much. It basically translates it into class-files / bytecode. In the bytecode there is a number called "max locals" which tells how many local variables are required to run the method.
The JVM on the other hand, which reads this information and runs the code makes sure memory is allocated on the stack frame to fit the required variables. How much it asks for is highly implementation dependent, and it may very well optimize the whole thing, and allocate fewer bytes than what's indicated by the code.
what happen to d. os creates a new memory address or it just reffer to the address of c as the value is same.
This is tagged Java. So let's keep the OS out of it. Everything happens in memory managed by the JVM, which is allocated in big chunks in advance.
You are talking about primitive data types. Those are easy, as they are stored by value, not as references to objects living elsewhere.
You are talking about local variables. Those are allocated on the running thread's call stack (not in heap memory). Since they are primitive here, too, this does not involve the heap at all.
In your case, there is memory allocated (on the stack), for the four integers. Each of them contains the value assigned to it, not a reference. Even if the same value is assigned to all of them, they exist separately. The memory is "freed" (not really freed, but no longer used by the thread) when the method returns.
If those were not integers, but Objects, you could "share pointers" (to objects on the heap), but integers are stored by value (four bytes each).

Do Java primitives go on the Stack or the Heap?

I just know that the non-primitives (the objects) go on the heap, and methods go on the stack, but what about the primitive variables?
--update
Based on the answers, I could say the heap can have a new stack and heap for a given object? Given that the object will have primitive and reference variables..?
Primitives defined locally would be on the stack. However if a primitive were defined as part of an instance of an object, that primitive would be on the heap.
public class Test {
private static class HeapClass {
public int y; // When an instance of HeapClass is allocated, this will be on the heap.
}
public static void main(String[] args) {
int x=1; // This is on the stack.
}
}
With regards to the update:
Objects do not have their own stack. In my example, int y would actually be part of each instance of HeapClass. Whenever an instance of HeapClass is allocated (e.g. new Test.HeapClass()), all member variables of HeapClass are added to the heap. Thus, since instances of HeapClass are being allocated on the heap, int y would be on the heap as part of an instance of HeapClass.
However, all primitive variables declared in the body of any method would be on the stack.
As you can see in the above example, int x is on the stack because it is declared in a method body--not as a member of a class.
All local variables (including method arguments) go on the stack; objects and all their fields are stored in the heap. Variables are always primitives or references to objects.
Java implementations may actually store objects on the heap in such a way that it still complies with the specification. Similarly local variables may be stored in registers or become indistinct through optimisation.
primitives can be found in both places.
class Foo
{
public int x;
public static void Main()
{
int y = 3; // y is on the stack
Foo f = new Foo(); // f.x is probably on the heap
}
}
except you shouldn't really care unless you're building a JVM. A really clever optimizer might decide that since the Foo that f points to never escapes Main, and is never passed to another function that it is safe to allocate it on the stack.
With regards to the update:
The stack and the heap aren't distinguished by what is stored in them, but rather the operations provided for them. The stack allows you to allocate a piece of memory in a LIFO fashion, you can't deallocate a piece until all the pieces younger than it have also been deallocated. This conveniently aligns with how a call stack is used. You can put anything on the stack as long as it is ok for that thing to go away when your function returns. This is an optimization, as it is very quick to allocate and deallocate from a stack since it only supports being used in this manner. One could store all the local variables for a function on the heap in an implementation if one wanted to. The heap is more flexible, and consequently more expensive to use. It would not be accurate to say that an object has a stack and a heap, as I said, what distinguishes the stack from the heap is not what is in it, but the available operations.
Primitive values are allocated on the stack unless they are fields of an object, in which case they go on the heap. The stack is used for evaluation and execution, so no it doesn't make sense to say that objects with primitive fields have a stack—it is still considered to be part of the heap. Even Stack objects are allocated on the heap.

Categories