当前位置: 首页 > 面试题库 >

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

邵弘致
2023-03-14
问题内容

最近,我一直在阅读有关Java中的内存分配方案的大量文章,并且由于我从各种来源中进行了阅读,所以存在很多疑问。我已经收集了我的概念,并要求仔细阅读所有要点并对其进行评论。我知道内存分配是特定于JVM的,因此我必须事先说一下,我的问题是特定于Sun的。

  1. 类(由类加载器加载)放在堆上的特殊区域中:永久生成
  2. 与类有关的所有信息,例如类的名称,与该类关联的对象数组,JVM使用的内部对象(例如java / lang / Object)以及优化信息,都进入了永久生成区域。
  3. 所有静态成员变量将再次保留在永久生成区域中。
  4. 对象放在不同的堆上:年轻的一代
  5. 每个类每个方法只有一个副本,该副本是静态的还是非静态的。该副本将放置在“永久生成”区域中。对于非静态方法,所有参数和局部变量都进入堆栈-每当对该方法进行具体调用时,我们都会获得一个与之关联的新堆栈框架。我不确定静态方法的局部变量存储在哪里。他们在永久一代的堆上吗?或者只是他们的引用存储在永久生成区域中,而实际副本位于其他位置(在哪里?)
  6. 我也不确定方法的返回类型存储在哪里。
  7. 如果对象(年轻一代)需要使用静态成员(永久一代),则为它们提供对静态成员的引用&&为它们提供足够的存储空间以存储方法的返回类型等。

问题答案:

首先,到现在应该让你清楚地知道,只有很少人可以凭第一手知识来确认这些答案。很少有人研究过最新的HotSpot JVM或对其进行深入研究以真正了解它们。此处的大多数人(包括我自己在内)都根据他们在其他地方看到的东西或他们推断出的内容进行回答。通常,此处或各式各样的文章和网页中所写内容均基于可能不确定的其他来源。通常,它是简化的,不准确的或完全是错误的。

如果你想确定答案,则确实需要下载OpenJDK源代码…并通过阅读和理解源代码进行自己的研究。在SO上提问或在随机Web文章中拖网都不是一种可靠的学术研究技术。

话说回来 …

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

AFAIK,是的。(更新:请参见下文。)

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

或多或少,是的。我不确定这些东西中的什么意思。我猜想“ JVM使用的内部对象(例如java / lang / Object)”是指JVM内部的类描述符。

3)所有静态成员变量再次保留在永久生成区域中。

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

4)对象放在不同的堆上:年轻的一代

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

5)每个类每个方法只有一个副本,该方法是静态的还是非静态的。该副本将放置在“永久生成”区域中。

假设你正在引用该方法的代码,则AFAIK是。不过,它可能要复杂一些。例如,在JVM生命周期的不同时间,该代码可能以字节码和/或本机代码形式存在。

…对于非静态方法,所有参数和局部变量都进入堆栈-每当对该方法进行具体调用时,我们都会获得一个与之关联的新堆栈框架。

是。

…我不确定静态方法的局部变量存储在哪里。他们在永久一代的堆上吗?或者只是他们的引用存储在永久生成区域中,而实际副本位于其他位置(在哪里?)

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

6)我也不确定方法的返回类型存储在哪里。

如果你的意思是(非无效)方法调用返回的值,那么它要么返回堆栈,要么返回到机器寄存器中。如果将其返回到堆栈上,则需要1或2个字,具体取决于返回类型。

7)如果对象(年轻代)需要使用静态成员(永久代),则为它们提供对静态成员的引用&&为它们提供足够的存储空间以存储方法的返回类型,等等。 。

那是不准确的(或者至少你没有清楚地表达自己的意思)。

如果某些方法访问静态成员变量,则它获得的要么是原始值,要么是对象引用。可以将其分配给(现有)局部变量或参数,分配给(现有)静态或非静态成员,分配给先前分配的数组的(现有)元素,或者简单地使用和丢弃它。

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

  • 通常,存储一个对象或数组引用只需要一个字的内存,根据硬件体系结构,原始值通常占用一个或两个字。

  • 在任何情况下,调用方都不需要分配空间来容纳方法返回的某些对象/数组。在Java中,对象和数组总是使用按值传递语义返回的……但是返回的值是对象或数组引用。



 类似资料:
  • 问题内容: 是局部变量,将其存储在堆或堆栈中的何处? 问题答案: 在堆上。每当您用来创建对象时,它都会在堆上分配。

  • 我试图了解分配给堆栈和堆的内存量。假设sizeof(char)=1字节,sizeof(void*)=4字节。给定以下代码: 我们被告知分配给堆的内存量是5个字节,我明白这确实是malloc(strlen(str2)=5)中的量。但是,我不明白的是分配给堆栈的内存量是如何达到18个字节的?我想如果他们给我们一个指针大小是4个字节的信息,那么我们有4个字节的指针str1和另外6个字节的数组str2(包

  • 问题内容: 有没有办法我可以在自己的计算机上为jvm设置默认堆大小?我想将其设置为1g,因为我一直在运行自定义程序,这些程序始终会达到默认jvm大小的超额点。 我只是不想记住每次我从命令行运行Java应用程序时都要键入-XmX1g … 必须有一种管理方式来做到这一点吗? 问题答案: 显然,它也可以在Linux上运行:

  • 本文向大家介绍JAVA中堆、栈,静态方法和非静态方法的速度问题,包括了JAVA中堆、栈,静态方法和非静态方法的速度问题的使用技巧和注意事项,需要的朋友参考一下 一、堆和栈的速度性能分析        堆和栈是JVM内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内容,存储空间大小,存储速度这几个方面来理解的,但是关于堆和栈的存储速度,只知道堆存储速度慢,栈存储速度快,

  • 我来自C/C++背景,在这里一个进程内存分为: null 我想把我的注意力集中在这一点上,当我阅读JVM中的堆和堆栈时,我们是在谈论堆栈和堆的概念吗?并且整个JVM的实际内存驻留在堆上(这里指的是堆的C++概念)?

  • JVM规范(JSE 8版)提到: 第12页:2.5.2 JVM堆栈:“因为JVM堆栈除了用于推送和弹出帧之外,从来没有被直接操作过,所以帧可以被堆分配。” 第15页:2.6:帧:“帧是从创建帧的线程的JVM堆栈中分配的。”在第16页:“请注意,由线程创建的框架是该线程的本地框架,不能被任何其他线程引用。” 这听起来让我很困惑。既然一个帧是创建该帧的线程本地的,为什么要在堆中分配该帧,因为堆在所有J