解释连续分配(堆栈中保存的内存)与堆中的内存之间的区别。
我是新手,并不完全确定。
答案 0 :(得分:1)
问题与堆不相连,而是自动与堆相关。
自动存储在进入代码块时设置 - 传统上在进入函数或方法时 - 并在该函数返回时被丢弃,因此堆栈上的内存空间可以被下一个函数调用重用。这就是大多数局部变量的处理方式。显然,这对于任何旨在持续超过该函数调用结束的内容都没有用。
在Java中,永远不会从自动存储中分配对象。相反,它们是在执行new
操作时根据需求从堆中分配的。有几个原因,坦率地说,除非你设计一种你真的不需要了解的编程语言,否则这个主题太大了。重要的是,由于它们是从堆中获取的,因此它们的生命周期与堆栈帧无关。由于Java是一种垃圾收集语言,它们的内存将在最后一次引用它们之后的某个时间自动恢复以供重用 - 再次,这里的细节太大了,但基本上你可以相信GC来了通过定期拿起我们丢弃在地板上的衣服然后将它们扔进洗衣房。
答案 1 :(得分:1)
当我们谈论记忆或光盘分配时,“连续”一词仅仅意味着“没有任何空白”。
单个堆栈或堆内存分配总是连续的...在我遇到过的每个编程语言运行时都谈到分配的意义。
如果各个分配之间没有差距,则一系列分配是连续的。
这与堆栈与堆栈正交。堆栈分配和堆分配都可以是连续的......或者是非连续的。
嗯......不太正交。
如果您正在讨论严格连续的内存地址(物理或虚拟),则典型的堆节点由应用程序可以使用的内存区域以及小节点标头组成。因此,如果查看两个连续堆节点的可用内存,则存在一个间隙...包含节点头...,可防止应用程序将两个区域用作单个连续区域。 (如果你覆盖节点标题,你最好不要尝试'cos,可能会发生不好的事情。)
然而,当我们谈论Java时,这是不相关的。 Java不允许应用程序将对象或数组连接在一起。 (这将严重违反运行时类型安全性。)因此,地址范围中的名义差距无关紧要。在Java上下文中,我们会说两个对象是连续的,忽略了堆节点/对象头。
此外,在Java中,您无法在堆上显式分配内容。在传统的JVM中,只有包含基本类型和引用的局部变量才会进入堆栈。没有办法说“在堆栈上分配这个数组”。 (JVM可能会在某些情况下执行后者,但它对应用程序完全透明,当然也不是您可以使用的东西。)
答案 2 :(得分:1)
堆栈帧仅在方法调用的生命周期中存在,这意味着分配内存为所有本地变量和方法参数提供存储,这些参数以某种方式使用,有助于帮助方法实现任何任务的目标它开始实现。
堆栈帧中的内存存储示例是临时指针,用于跟踪正在迭代的数组中的索引位置。循环完成后,堆栈框架将从堆栈中弹出,这意味着为局部变量和方法参数分配的所有临时内存都将释放回系统。
堆是不同的,因为它是对象所在的位置,而不是对象的“指针”。
当我在学习时,我发现很难弄清楚两者之间的区别。 帮助我的关键点是,指向对象的指针保存在堆栈帧中,它有一点临时内存分配,在方法调用的生命周期中存在。因此,只有在方法处于“范围”时才能访问对象。
指针包含一个内存地址,该地址指向存储在堆上的对象的位置。这允许您引用对象以在以后更改对象状态。
public static void main(String[] args)
{
Person person = new Person("Steven", 30);
}
运行此程序时:
要理解的重要部分是,存储对象方法不需要内存。调用方法时,会创建一个新的堆栈帧,在方法调用期间分配临时内存。使用上面的示例,Person有2个实例变量,一个String名称和int age。这意味着此Person对象所需的内存是存储String类型的引用变量所需的内存(堆上String对象的内存地址的位模式)和保存位的内存int的模式。
最后,main方法也是一个堆栈框架,所以当main完成时,你不再有对Person对象的引用或者对main中可能存在的任何临时变量的访问。
对于任何方法都是如此,如果你有一个方法创建一个对象但是没有返回对该对象的引用,那么你永远不能访问该对象,并且Java垃圾收集器会在以后出现并清理堆上的所有对象都没有指向它们的引用。
如果你刚开始,我强烈推荐首先是java。这是一本很棒的IMO书,以易于理解的方式介绍这些主题。