堆,堆栈和永久代
我最近一直在用java读取很多内存分配方案,并且在我从各种渠道阅读时遇到了许多疑问。 我已经收集了我的概念,并且我会请求通读所有观点并对它们发表评论。 我开始知道内存分配是特定于JVM的,所以我必须事先说,我的问题是Sun特有的。
感谢您通过这个!
首先,现在应该清楚的是,很少有人能够从第一手知识中确认这些答案。 很少有人在最近的HotSpot JVM上工作,或者研究他们到真正需要的深度。 这里的大多数人(包括我自己)都是根据他们在其他地方看到的内容或他们推断出的内容来回答问题。 通常,这里或各种文章和网页上所写的内容是基于其他来源,这些来源可能是或可能不是明确的。 通常它是简化的,不准确的或者明显的错误。
如果你想确定你的答案,你真的需要下载OpenJDK源代码......并通过阅读和理解源代码来做你自己的研究。 在SO上提出问题,或者通过随机的网络文章进行搜索并不是一种合理的学术研究技术。
话说回来 ...
1)类(由类加载器加载)进入堆中的特殊区域:永久生成。
AFAIK,是的。 ( 更新 :见下文)
2)所有与像类名相关的类,与类关联的对象数组,与JVM使用的内部对象(如java / lang / Object)和优化信息有关的所有信息都会进入永久生成区域。
或多或少,是的。 我不确定你说的这些东西是什么意思。 我猜测“JVM使用的内部对象(如java / lang / Object)”意味着JVM内部的类描述符。
3)所有的静态成员变量都保存在永久生成区域中。
变量本身是的。 这些变量(如所有Java变量)将保存原始值或对象引用。 但是,虽然静态成员变量位于permgen堆中分配的框架中,但这些变量引用的对象/数组可能会分配到任何堆中。
4)对象走上另一堆:年轻一代
不必要。 大型对象可以直接分配到终身代。
5)每个类的每个方法只有一个副本,方法是静态或非静态的。 该副本放在永久代区域。
假设你指的是方法的代码,那么AFAIK是。 不过,这可能会稍微复杂一些。 例如,该代码可能在JVM生命周期的不同时间以字节码和/或本地代码形式存在。
...对于非静态方法,所有参数和局部变量都会进入堆栈 - 每当有该方法的具体调用时,我们就会得到一个与之关联的新栈帧。
是。
...我不确定静态方法的局部变量存储在哪里。 他们是否在永久变形的堆上? 或者只是将他们的参考文件存储在永久生成区域中,而实际的副本位于其他位置(哪里?)
不,它们存储在堆栈中,就像非静态方法中的局部变量一样。
6)我也不确定方法的返回类型存储在哪里。
如果你的意思是(非void)方法调用返回的值,那么它会在堆栈或机器寄存器中返回。 如果在堆栈中返回,则根据返回类型,这需要1或2个单词。
7)如果对象(年轻一代)需要使用一个静态成员(在永久代),它们被赋予一个静态成员&&的引用,它们被赋予足够的内存空间来存储方法的返回类型等。 。
这是不准确的(或者至少,你没有明确表达自己)。
如果某个方法访问一个静态成员变量,它得到的是一个原始值或一个对象引用 。 这可以被分配给分配给(现有的)静态或非静态成员,分配给先前分配数组的(现有)元素的(现有的)本地变量或参数,或者简单地使用和丢弃。
在任何情况下都不需要分配新的存储空间来保存参考值或原始值。
通常,存储器的一个字是存储对象或数组引用所需的全部内容,并且取决于硬件体系结构,原始值通常占用一个或两个字。
在任何情况下,调用者都不需要分配空间来容纳方法返回的某个对象/数组。 在Java中,对象和数组总是使用按值传递语义返回......但返回的值是对象或数组引用。
UPDATE
从Java 8开始,PermGen空间已被Metaspace所取代。 有关更多信息,请参阅以下资源: