2

This is part of the answer about stack and heap in Java:

So, why have the stack or the heap at all? For things that leave scope, the stack can be expensive. Consider the code:

void foo(String arg) {
    bar(arg);
    ...
}

void bar(String arg) {
    qux(arg);
    ...
}

void qux(String arg) {
    ...
}

The parameters are part of the stack too. In the situation that you don't have a heap, you would be passing the full set of values on the stack. This is fine for "foo" and small strings... but what would happen if someone put a huge XML file in that string. Each call would copy the entire huge string onto the stack - and that would be quite wasteful.


This is what I read in The Java ® Virtual Machine Specification Java SE 8 Edition (Chapter 2.5.2. Java Virtual Machine Stacks):

It [Java Virtual Machine stack] holds local variables and partial results, and plays a part in method invocation and return.


What I know is that when I pass a reference as a parameter to a method, a local variable is created inside the method. The local variable holds the same reference as the passed variable. For example, something like this

void foo(Bar bar) {
    // Do something with bar
}

turns into something like this:

void foo(Bar bar) {
    Bar localBar = bar;
    // Do something with localBar
}

So my question is:

Does Java copy method parameters to the stack frame of the called method? From the answer I refer to at the start of page, I understand they are copied, and it's a deep copy. Almost sure, I am wrong.

2 Answers 2

7

In Java, the distinction stack vs. heap is not very meaningful, because Java doesn't give you a choice where values live. Conceptually, all objects live somewhere on the heap, but in Java an object is not the same thing as a variable. Local variables and method parameters use space on the stack, but variables never hold an object directly. The variables either contain primitive values like int, or references to objects.

In Java, variable assignment always performs a shallow copy: for primitive values, the value is copied. For objects, the reference is copied. The object that is referenced is not copied: the original reference and the copied reference both refer to the same object.

Method calls work very much like variable assignment to the parameters. When a method is called, you can think that a stack frame with the method parameters is allocated on the stack, and that we then assign the argument values to each parameter variable.

Because a shallow copy of all argument values is performed, you cannot change outside variables by assigning to a parameter within a method:

void outer() {
  int i = 4;
  inner(i);
  // i will always be 4 at this point
}

void inner(int j) {
  j = 7;  // this assignment only affects the *local* j
}

But if you pass an object there is no deep copy, so changes to the object are visible outside of the method:

void outer() {
  ArrayList<String> xs = new ArrayList<>();
  inner(xs);
  // xs has been modified at this point, and contains "foo"
}

void inner(ArrayList<String> ys) {
  ys.add("foo");
}

The part from the answer that you quoted does not explain how Java works, but why it is desirable to not do deep copies for each method call.

The behaviour of Java's method calls is very similar to C and C++: everything is passed by value. The difference is that Java objects are not an object in the C and C++ sense, but behave like a pointer to the actual object. For variable assignment and method calls, that pointer is then passed by value.

3
  • Indeed, the part of the answer, I quoted, explains what would happen if there was no heap memory. But suppose there is no heap. In ideone.com/RZAG70 the call stack is [foo, bar, lorem], and lorem is popped off the stack first. str is preserved as long as it's needed. How can I refer to it in bar and lorem? Suppose I can read it from the stack frame of foo. Which already looks like a code smell. Commented May 28, 2017 at 13:00
  • I you had no heap, argument-passing wouldn't change. What would change is returning results, as you would need to reserve the space for result-objects somehow somewhere. Commented May 28, 2017 at 13:30
  • 1
    @MaksimDmitriev Even if there were no heap, that doesn't mean arguments need to be copied. If an object is allocated in an older part of the stack, pointers to this object can be passed as arguments, so newer stack frames can access the string. The stack would have to look like [str, foo frame, bar frame, lorem frame]. But because data on the stack cannot outlive the stack frame it was allocated in, it becomes more awkward to write some programs. Note that “code smells” don't matter for the inner workings of a language.
    – amon
    Commented May 28, 2017 at 13:34
0

In Java, you have objects (all inheriting from java.lang.Object, heap-allocated) and primitive types (bool, char, integer types, float, double, as well as pointers to objects (called references for marketing purposes)).

Variables are of primitive type, thus trivially copied, and always passed by value.

Objects cannot be passed at all, but pointers to them can, effectively passing them by reference, not copying them.

Deep copies of a primitive type are the same as shallow copies.
Copies of objects don't happen at all unless you explicitly make them, and then it's your own responsibility to do/avoid structure sharing as appropriate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.