首页 文章

java中的静态分配 - 堆,堆栈和永久生成

提问于
浏览
102

我最近在java中的内存分配方案上已经阅读了很多内容,而且我从各种来源阅读时都有很多疑问 . 我已经收集了我的概念,并且我会要求完成所有要点并对它们进行评论 . 我开始知道内存分配是特定于JVM的,所以我必须事先说,我的问题是Sun特定的 .

  • 类(由类加载器加载)进入堆上的特殊区域:永久生成

  • 与类的名称,与类关联的对象数组,JVM使用的内部对象(如java / lang / Object)和优化信息等类相关的所有信息都进入永久生成区域 .

  • 所有静态成员变量再次保留在“永久生成”区域中 .

  • 对象进入不同的堆:年轻一代

  • 每个类只有一个方法的副本,无论是静态还是非静态方法 . 该副本放在永久生成区域 . 对于非静态方法,所有参数和局部变量都会进入堆栈 - 只要对该方法进行具体调用,我们就会得到一个与之关联的新堆栈帧 . 我不确定静态方法的局部变量存储在哪里 . 他们是永久世代的堆吗?或者只是他们的引用存储在Permanent Generation区域,而实际的副本是在其他地方(Where?)

  • 我也不确定方法的返回类型存储在何处 .

  • 如果对象(在年轻代中)需要使用静态成员(在永久代中),则会给它们一个静态成员的引用&&它们被赋予足够的内存空间来存储方法的返回类型等 .

谢谢你通过这个!

1 回答

  • 136

    首先,您现在应该清楚,很少有人可以从第一手知识中确认这些答案 . 很少有人在最近的HotSpot JVM上工作或研究它们到真正需要的深度 . 这里的大多数人(包括我自己)都是基于他们在其他地方写过的东西,或者他们所推断的东西来回答 . 通常,此处或各种文章和网页中所写的内容基于其他来源,这些来源可能是也可能不是明确的 . 通常它是简化的,不准确的或完全错误的 .

    如果您想要明确确认答案,您确实需要下载OpenJDK源代码......并通过阅读和理解源代码进行自己的研究 . 询问关于SO的问题,或通过随机网络文章进行拖网搜索并不是一种合理的学术研究技术 .

    话说回来 ...

    1)类(由类加载器加载)进入堆上的特殊区域:永久生成 .

    AFAIK,是的 . ( Update :见下文 . )

    2)与类的名称,与类关联的对象数组,JVM使用的内部对象(如java / lang / Object)和优化信息等类相关的所有信息都进入永久生成区域 .

    或多或少,是的 . 我不确定你的意思是什么 . 我猜测“JVM使用的内部对象(如java / lang / Object)”意味着JVM内部类描述符 .

    3)所有静态成员变量再次保留在Permanent Generation区域 .

    变量本身是的 . 这些变量(与所有Java变量一样)将包含原始值或对象引用 . 但是,虽然静态成员变量位于permgen堆中分配的帧中,但这些变量引用的对象/数组可以在任何堆中分配 .

    4)物体进入不同的堆:年轻一代

    不必要 . 大型对象可以直接分配给终身代 .

    5)每个类只有一个方法的副本,是静态或非静态方法 . 该副本放在永久生成区域 .

    假设您指的是方法的代码,那么AFAIK是的 . 但它可能有点复杂 . 例如,代码可能在JVM生命期间的不同时间以字节码和/或本机代码形式存在 .

    ...对于非静态方法,所有参数和局部变量都会进入堆栈 - 只要对该方法进行具体调用,我们就会得到一个与之关联的新堆栈帧 .

    是 .

    ...我不确定静态方法的局部变量存储在哪里 . 他们是永久世代的堆吗?或者只是他们的引用存储在Permanent Generation区域,而实际的副本是在其他地方(Where?)

    不会 . 它们存储在堆栈中,就像非静态方法中的局部变量一样 .

    6)我也不确定方法的返回类型存储在何处 .

    如果您指的是(非void)方法调用返回的值,则它将在堆栈或机器寄存器中返回 . 如果它在堆栈上返回,则需要1或2个单词,具体取决于返回类型 .

    7)如果对象(在年轻代中)使用静态成员(在永久代中),它们被赋予对静态成员的引用&&它们被给予足够的存储空间来存储方法的返回类型等 .

    这是不准确的(或至少,你没有表达自己清楚) .

    如果某个方法访问静态成员变量,它获取的是原始值或对象 reference . 这可以分配给(现有的)局部变量或参数,分配给(现有的)静态或非静态成员,分配给先前分配的数组的(现有)元素,或者简单地使用和丢弃 .

    • 在任何情况下都不需要分配新存储来保存引用值或原始值 .

    • 通常,存储一个字是存储对象或数组引用所需的全部内容,而原始值通常占用一个或两个字,具体取决于硬件架构 .

    • 在任何情况下,调用者都不需要分配空间来保存方法返回的某个对象/数组 . 在Java中,始终使用按值传递语义返回对象和数组...但返回的值是对象或数组引用 .

    UPDATE

    从Java 8开始,PermGen空间已被Metaspace取代 . 有关更多信息,请参阅以下资源:

相关问题