Java int内存使用率

Java int内存使用率,java,arrays,memory,jvm,int,Java,Arrays,Memory,Jvm,Int,当我考虑各种类型的内存使用时,我开始对Java在传递给方法时如何利用整数内存感到困惑 比如说,我有以下代码: public static void main (String[] args){ int i = 4; addUp(i); } public static int addUp(int i){ if(i == 0) return 0; else return addUp(i - 1); } 在下面的示例中,我想知道我的以下逻辑是

当我考虑各种类型的内存使用时,我开始对Java在传递给方法时如何利用整数内存感到困惑

比如说,我有以下代码:

public static void main (String[] args){
     int i = 4;
     addUp(i);
}

public static int addUp(int i){
     if(i == 0) return 0;
     else return addUp(i - 1);         
}
在下面的示例中,我想知道我的以下逻辑是否正确:

  • 我最初为整数I=4创建了一个内存。然后我将其传递给一个方法。但是,由于原语在Java中不是指向的,因此在加法(i==4)中,我创建了另一个整数i=4。然后,还有另一个加法(i==3)、加法(i==2)、加法(i==1)、加法(i==0),由于没有指向该值,因此每次都会在内存中分配一个新的i值
  • 对于一个“inti”值,我使用了6个整数值存储器
但是,如果我总是通过数组传递它:

public static void main (String[] args){
     int[] i = {4};
     // int tempI = i[0];
     addUp(i);
}

public static int addUp(int[] i){
     if(i[0] == 0) return 0;
     else return addUp(i[0] = i[0] - 1);         
}
-由于我创建了一个大小为1的整数数组,然后将其传递给addUp,而addUp将再次传递给addUp(I[0]==3)、addUp(I[0]==2)、addUp(I[0]==1)、addUp(I[0]==0),因此我只需使用1个整数数组内存空间,因此更具成本效益。此外,如果我要预先生成一个int值来存储I[0]的初始值,那么我仍然有我的“原始”值


这就引出了一个问题,为什么人们在Java方法中传递int这样的原语?仅仅传递这些原语的数组值不是内存效率更高吗?还是第一个例子仍然只是O(1)内存

在这个问题上,我只是想知道使用int[]和int的内存差异,特别是对于1的大小。先谢谢你。我只是想知道如何使用Java来提高内存效率,我想到了这一点

谢谢你的回答!我现在很快就想知道,如果我要“分析”每段代码的大内存,它们会被认为是O(1)还是假设是错误的


传递数组时,接收数组的方法可能会修改数组的内容。传递int基元时,接收它们的方法可能不会修改这些基元。这就是为什么有时可以使用原语,有时使用数组


一般来说,在Java编程中,您倾向于支持可读性,并让这种内存优化由JIT编译器完成。

int数组引用实际上比int原语(8字节vs 4字节)在堆栈帧中占用更多的空间。实际上,您正在使用更多的空间

但我认为人们喜欢第一种方式的主要原因是它更清晰易读


当涉及到更多的int时,人们实际上做的事情更接近于第二个int。

这里缺少的是:示例中的int值位于上,而不是堆上

与堆上的对象相比,处理堆栈上存在的固定大小原语值的开销要小得多

换句话说:使用“指针”意味着您必须在堆上创建一个新对象。所有对象都位于堆上;没有用于阵列的堆栈!在您停止使用对象后,对象将立即被垃圾收集。另一方面,堆栈在调用方法时来来去去去

除此之外:请记住,编程语言提供给我们的抽象是为了帮助我们编写易于阅读、理解和维护的代码。您的方法基本上是进行某种微调,从而生成更复杂的代码。Java并不是这样解决这些问题的

含义:对于Java,真正的“性能魔法”发生在运行时,即即时编译器启动时!你看,当调用小方法“足够频繁”时,JIT可以内联调用小方法。然后,保持数据“紧密”在一起变得更加重要。如中所示:当数据位于堆上时,您可能必须访问内存才能获取值。然而,堆栈上的项可能仍然“关闭”(如:在处理器缓存中)。因此,优化内存使用的小想法实际上可以将程序执行速度降低几个数量级。因为即使在今天,在访问处理器缓存和读取主内存之间也存在数量级的差别

长话短说:避免对性能或内存使用进行这种“微调”:JVM针对“正常、典型”用例进行了优化。因此,您尝试引入巧妙的变通方法很容易导致“不太好”的结果

所以-当你担心表现时:做其他人都在做的事情。如果你真的关心JVM,那么就学习JVM是如何工作的。事实证明,即使是我的知识也有点过时——因为注释暗示JIT可以在堆栈上内联对象。从这个意义上说:专注于编写干净、优雅的代码,以直截了当的方式解决问题


最后:这可能会在某个时候发生变化。有一些想法可以将真值对象引入java。它们基本上生活在堆栈上,而不是堆上。但不要期望在Java10之前发生这种情况。或11。或(我认为与此相关)。

如果您的假设是传递给函数的参数必然会消耗内存(顺便说一句,这是错误的),那么在传递数组的第二个示例中,将创建对数组引用的副本。该引用实际上可能大于int,但不太可能小于int。

有几点:

首先要做的事情是分门别类,但是当您在java中传递一个int时,您在堆栈中分配了4个字节,当您传递一个数组(因为它是一个引用)时,您实际上在堆栈中分配了8个字节(假设是x64体系结构),加上将int存储到堆中的额外4个字节

更重要的是,数组中的数据被分配到堆中,而对数组本身的引用被分配到堆栈中
public static int addUp(int i){
     while(i != 0) i = i-1 ;
     return 0;        
}
public static int addUp(int[] i){
     while(i[0] != 0) i[0] = i[0] - 1 ;
     return 0 ;
}