Java中的参数内存分配

时间:2016-09-07 13:23:22

标签: java jvm language-lawyer jvm-bytecode

以下语句中的数据是存储为自动内存分配,动态内存分配还是两者都存储

myFunction(new MyClass());

谢谢!

4 个答案:

答案 0 :(得分:2)

术语“自动内存分配”和“动态内存分配”在Java的上下文中没有意义。在Java中,所有内存都由执行环境管理。

在其他编程语言中,术语“自动存储”和“动态存储”用于区分存储(在超出范围时自动解除分配)和存储(需要明确存储)应用程序执行的 deallocation 操作。在Java中,根本没有明确的解除分配。您会发现人和文献继续区分堆栈和堆,其中只有后者包含对象,其生命周期可能超过创建它们的方法的执行。但是,这只是一种逻辑分离,可能无法反映特定JVM实现的实际工作方式。

Java® Language Specification并没有详细说明这方面的工作。只有两个点:

  

15.12.4.5. Create Frame, Synchronize, Transfer Control

     

某个类m中的方法S已被识别为要调用的方法。

     

现在创建了一个新的激活框架,其中包含目标引用(如果有)和参数值(如果有的话),以及足够的空间用于本地变量和方法的堆栈被调用以及实现可能需要的任何其他簿记信息(堆栈指针,程序计数器,对先前激活帧的引用等)。如果没有足够的可用内存来创建这样的激活帧,则会抛出StackOverflowError

  

17.4.1. Shared Variables

     

可以在线程之间共享的内存称为共享内存堆内存

     

所有实例字段,static字段和数组元素都存储在堆内存中。在本章中,我们使用术语变量来引用字段和数组元素。

     

局部变量(第14.4节),形式方法参数(第8.4.1节)和异常处理程序参数(第14.20节)永远不会在线程之间共享,并且不受内存模型的影响。

请注意,这是唯一一个将术语“堆”用作内存类型的地方,以及实际在此定义的方式......

部分§15.9.4. Run-Time Evaluation of Class Instance Creation Expressions§15.10.2. Run-Time Evaluation of Array Creation Expressions更加模糊,说“空间已分配”,如果空间不足,则会抛出OutOfMemoryError,仅此而已。

因此,如果您采用区分堆栈和堆的路径,您可以说您的代码myFunction(new MyClass());将导致MyClass实例的堆分配,然后是激活的堆栈分配myFunction方法的实际实现框架。并不是说它对任何实际目的都很重要。

如果你想深入研究,JVM可能会实现它,你可以参考Java® Virtual Machine Specification代替:

  

2.5.2. Java Virtual Machine Stacks

     

每个 Java虚拟机线程都有一个私有Java虚拟机堆栈,与线程同时创建。 Java虚拟机堆栈存储帧(第2.6节)。 Java虚拟机堆栈类似于传统语言的堆栈,例如C:它保存局部变量和部分结果,并在方法调用和返回中起作用。由于除了推送和弹出帧之外,永远不会直接操作Java虚拟机堆栈,因此可以对堆进行堆分配。 Java虚拟机堆栈的内存不需要是连续的。

  

2.5.3. Heap

     

Java虚拟机有一个,它在所有Java虚拟机线程之间共享。堆是运行时数据区,从中分配所有类实例和数组的内存。

     

在虚拟机启动时创建堆。对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;对象永远不会被显式释放。 Java虚拟机假设没有特定类型的自动存储管理系统,可以根据实现者的系统要求选择存储管理技术。堆可以具有固定大小,或者可以根据计算的需要进行扩展,并且如果不需要更大的堆,则可以收缩。堆的内存不需要是连续的

注意,这些定义如何仅在它们的目的上有所不同,同时它们的约束没有显着差异,即可能是固定大小或可调整大小并且可能是连续的或不是,更不用说明确提到分配堆栈的可能性堆上的帧。

答案 1 :(得分:1)

Java中有三组内存

  1. - 这是在您调用new MyClass()时创建和定位对象的位置;
  2. 堆栈 - 堆栈包含堆栈帧,堆栈帧具有为基元分配的空间和指向堆中对象的指针。堆栈帧在方法调用上分配,并在方法返回
  3. 上解除分配
  4. 字符串常量:在编译时定义的字符串文字将添加到String常量池中。在运行时,可以使用String.intern()
  5. 将字符串添加到池中

    就是这样

答案 2 :(得分:1)

您的示例中分配了两件事情;

  1. 表达式new MyClass()在对象堆上分配MyClass的实例。

  2. new表达式的结果是对象引用。对象引用保存在激活记录中,用于调用myFunction()。激活记录在调用线程的调用堆栈上分配。

答案 3 :(得分:1)

当你创建一个新对象时,它经常在堆上分配,但是通过转义分析,它可以被解压缩到堆栈上,好像它是一个局部变量。

唯一的分配是通过new或捕获lambda(或极少数情况下的一些本机方法)。分配对象的不同方式之间没有任何明确的区别。