java Java堆栈和堆内存管理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41120129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:41:59  来源:igfitidea点击:

Java stack and heap memory management

javamemorymemory-managementheap-memorystack-memory

提问by Adit A. Pillai

I want to know how the memory is being allocated in the following program:

我想知道以下程序中的内存是如何分配的:

public class MemoryClass {

    public static void main(final String[] args) {
        int i = 0;
        MemoryClass memoryClass = new MemoryClass();
        memoryClass.myMethod(memoryClass);
    }

    private void myMethod(final Object obj) {
        int i = 1;
        String s = "HelloWorld!";

    }

}

Now, as far as my understanding goes, the following diagram describes how the memory allocation takes place:
Basic runtime memory allocation

现在,据我所知,下图描述了内存分配是如何发生的:
基本运行时内存分配


In the above diagram, memory,objand s, which are in the stack memory, are actually the references to their "actual objects" which are placed inside the heap memory.
Here is the set of questions that come to my mind:


在上图中,内存objs位于堆栈内存中,实际上是对其放置在堆内存中的“实际对象”的引用。
以下是我想到的一系列问题:

  1. Where are the methods of sstored?
  2. Had I created another object of MemoryClassinside myMethod, would JVM allocate memory for the same methods again inside the stack memory?
  3. Would JVM free the memory allocated to myMethodas soon as it's execution is completed, if so, how would it manage the situation mentioned in question 2(only applicable if JVM allocates memory multiple times to the same method).
  4. What would have been the case, if I had only declared sand did not initialize it, would JVM still allocate memory to all the methods of java.lang.Stringclass,if so,why?
  1. s的方法存储在哪里?
  2. 如果我创建了另一个MemoryClassinside对象myMethod,JVM 会在堆栈内存中再次为相同的方法分配内存吗?
  3. JVMmyMethod是否会在执行完成后立即释放分配给的内存,如果是这样,它将如何管理问题 2 中提到的情况(仅适用于 JVM 多次为同一方法分配内存的情况)。
  4. 会是什么情况,如果我只声明了s而没有初始化它,JVM 还会为java.lang.String类的所有方法分配内存,如果是,为什么?

采纳答案by arcy

Where are the methods of s stored?

s 的方法存储在哪里?

They are stored in the String class object; it is an object loaded by a ClassLoader object when String is first referenced in the program. All the implementations of the JVM that existed when I read about this last never deallocated the memory for a class object once it was loaded. It's on the heap.

它们存储在 String 类对象中;它是在程序中首次引用 String 时由 ClassLoader 对象加载的对象。当我读到最后一篇文章时,JVM 的所有实现都没有在类对象加载后释放内存。它在堆上。

Had I created another object of MemoryClass inside myMethod, would JVM allocate memory for the same methods again inside the stack memory?

如果我在 myMethod 中创建了另一个 MemoryClass 对象,JVM 会在堆栈内存中再次为相同的方法分配内存吗?

No, methods and data for objects is kept separately, specifically because the JVM never needs more than one copy of the methods.

不,对象的方法和数据是分开保存的,特别是因为 JVM 永远不需要多个方法的副本。

Would JVM free the memory allocated to myMethod as soon as it's execution is completed, if so, how would it manage the situation mentioned in question 2(only applicable if JVM allocates memory multiple times to the same method).

JVM 是否会在 myMethod 执行完成后立即释放分配给 myMethod 的内存,如果是这样,它将如何管理问题 2 中提到的情况(仅适用于 JVM 多次为同一方法分配内存的情况)。

No. Java doesn't generally "immediately free memory" of things stored on the heap. It would make things run too slowly. It only frees memory when the garbage collector runs, and it does that only when its algorithm for running the garbage collector decides it is time.

不。Java 通常不会“立即释放内存”存储在堆上的东西。它会使事情运行得太慢。它仅在垃圾收集器运行时释放内存,并且仅在其运行垃圾收集器的算法确定时间到时才会释放内存。

What would have been the case, if I had only declared s and did not initialize it, would JVM still allocate memory to all the methods of java.lang.String class,if so,why?

会是什么情况,如果我只声明了s而不初始化它,JVM还会为java.lang.String类的所有方法分配内存,如果是,为什么?

This depends on the JVM implementation, I think, and maybe the compiler. If you declare a variable and never use it, it is quite possible (and common) for the compiler to notice that there is no use for it and to not put it into the class file. If it isn't in the class file, it is never referenced, and therefore it and its methods are not loaded, etc. If the compiler puts it in anyway but it is never referenced, then the ClassLoader wouldn't have any reason to load it, but I'm a little vague on whether it would get loaded or not. Might depend on the JVM implementation; does it load things because there are variables of the class or only when they are referenced? How many ClassLoader algorithms can dance on the head of a 4-digit PIN?

我认为这取决于 JVM 实现,也可能取决于编译器。如果您声明了一个变量并且从不使用它,编译器很可能(并且很常见)注意到它没有用处并且不将它放入类文件中。如果它不在类文件中,则永远不会被引用,因此不会加载它及其方法等。加载它,但我对它是否会加载有点含糊。可能取决于 JVM 实现;它加载东西是因为有类的变量还是只有当它们被引用时?有多少类加载器算法可以在 4 位 PIN 的头部跳舞?

I encourage you to read about the JVM and ClassLoaders and such; you will gain so much more by reading an explanation of how it works rather than poking at it with examples you can think up.

我鼓励您阅读有关 JVM 和 ClassLoader 等的内容;通过阅读它如何工作的解释,而不是用你能想到的例子来戳它,你会收获更多。

回答by hagrawal

First things first: I am assuming your questions are coming out after reading thisarticle (because over there I see a very similar diagram as yours) so I will not quote or highlight any of the points which are mentioned over there and will try to answer to your questions with points which were not so obvious in that post.

第一件事:我假设你的问题是在阅读这篇文章后出来的(因为在那里我看到一个与你非常相似的图表)所以我不会引用或强调那里提到的任何要点,并会尝试回答对你的问题提出了在那篇文章中不太明显的问题。

Reading to all your questions, my impression is that you are clear about how memory is allocated in stack and heap but have doubts about metadata of the classes i.e. where in the memory, methods of the classes would be stored and how they would be recycled. So, first let me try to explain JVM memory areas:

阅读您所有的问题,我的印象是您很清楚如何在堆栈和堆中分配内存,但对类的元数据有疑问,即在内存中的位置、类的方法将被存储以及它们将如何被回收。所以,首先让我试着解释一下 JVM 内存区域:



JVM Memory Areas

JVM 内存区域

Let me start by putting these 2 diagrams depicting JVM memory areas:

让我先把这两张图描绘 JVM 内存区域:

Source of diagram

图表来源

enter image description here

在此处输入图片说明

Source of diagram

图表来源

enter image description here

在此处输入图片说明

Now, as clear from the above diagrams below is the tree structure of JVM memory and I will try to throw light on the same (@Adit: please note that area which concerns you is PermGen Space or permanent generation space of non-heap memory).

现在,从上图可以清楚地看到 JVM 内存的树状结构,我将尝试阐明这一点@Adit:请注意您关注的区域是 PermGen Space 或非堆内存的永久代空间) .

  • Heap memory
    • Young generation
      • Eden Space
      • Survivor Space
    • Old generation
      • Tenured Generation
  • NonHeap memory
    • Permanent Generation
    • Code Cache (I think included "only" by HotSpot Java VM)
  • 堆内存
    • 年轻一代
      • 伊甸空间
      • 幸存者空间
    • 老一辈
      • 老一代
  • 非堆内存
    • 永久一代
    • 代码缓存(我认为“仅”包含在 HotSpot Java VM 中

Heap memory

堆内存

Heap memory is the runtime data area from which the Java VM allocates memory for all class instances and arrays. The heap may be of a fixed or variable size. The garbage collector is an automatic memory management system that reclaims heap memory for objects.

堆内存是 Java VM 为所有类实例和数组分配内存的运行时数据区域。堆的大小可以是固定的,也可以是可变的。垃圾收集器是一种自动内存管理系统,可以为对象回收堆内存。

Young generation

年轻一代

Young generation is the place where all the new objects are created. When young generation is filled, garbage collection is performed. This garbage collection is called Minor GC. Young Generation is divided into below 2 parts

年轻代是创建所有新对象的地方。当年轻代被填满时,进行垃圾收集。这种垃圾回收称为 Minor GC。年轻代分为以下两部分

Eden space:The pool from which memory is initially allocated for most objects.

伊甸园空间:最初为大多数对象分配内存的池。

Survivor space:The pool containing objects that have survived the garbage collection of the Eden space.

Survivor 空间:包含在 Eden 空间的垃圾收集中幸存下来的对象的池。

Old generation

老一辈

Old Generation memory contains the objects that are long lived and survived after many rounds of Minor GC. Usually garbage collection is performed in Old Generation memory when it's full. Old Generation Garbage Collection is called Major GC and usually takes longer time. Old generation contains below part:

老年代内存包含经过多轮 Minor GC 后长期存活并存活的对象。通常垃圾收集在老年代内存满时执行。Old Generation Garbage Collection 称为 Major GC,通常需要更长的时间。老年代包含以下部分:

Tenured space:The pool containing objects that have existed for some time in the survivor space.

永久空间:包含在幸存者空间中存在一段时间的对象的池。

Non-Heap memory

非堆内存

Non-heap memory includes a method area shared among all threads and memory required for the internal processing or optimization for the Java VM. It stores per-class structures such as a runtime constant pool, field and method data, and the code for methods and constructors. The method area is logically part of the heap but, depending on the implementation, a Java VM may not garbage collect or compact it. Like the heap memory, the method area may be of a fixed or variable size. The memory for the method area does not need to be contiguous.

非堆内存包括所有线程共享的方法区和 Java VM 内部处理或优化所需的内存。它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码。方法区在逻辑上是堆的一部分,但根据实现,Java VM 可能不会对其进行垃圾收集或压缩。与堆内存一样,方法区的大小可能是固定的,也可能是可变的。方法区的内存不需要是连续的。

Permanent generation

永久代

The pool containing all the reflective data of the virtual machine itself, such as class and method objects. With Java VMs that use class data sharing, this generation is divided into read-only and read-write areas.

该池包含虚拟机本身的所有反射数据,例如类和方法对象。对于使用类数据共享的Java VM,这一代分为只读和读写区域。

Code cache

代码缓存

The HotSpot Java VM also includes a code cache, containing memory that is used for compilation and storage of native code.

HotSpot Java VM 还包括一个代码缓存,其中包含用于编译和存储本机代码的内存。



Answering OP's questions specifically

专门回答OP的问题

Where are the methods of s stored?

s 的方法存储在哪里?

Non-Heap memory --> Permanent Generation

非堆内存 --> 永久代

Had I created another object of MemoryClass inside myMethod, would JVM allocate memory for the same methods again inside the stack memory?

如果我在 myMethod 中创建了另一个 MemoryClass 对象,JVM 会在堆栈内存中再次为相同的方法分配内存吗?

Stack memory only contains local variables so your ORV (object reference variable) of new MemoryClasswould still be created in stack frame of myMethod, but JVM would not load all the methods, metadata etc. of MemoryClassagain in "Permanent Generation".

堆栈内存仅包含局部变量,因此您的 new 的 ORV(对象引用变量)MemoryClass仍将在 的堆栈帧中创建myMethod,但 JVM 不会MemoryClass在“永久生成”中再次加载所有方法、元数据等。

JVM loads class only once and when it loads the class then space is allocated on "Permanent Generation" for that class and that happens only once while the class is loaded by JVM.

JVM 只加载一次类,当它加载类时,就会在“永久生成”上为该类分配空间,并且在 JVM 加载类时只会发生一次。

Would JVM free the memory allocated to myMethod as soon as it's execution is completed, if so, how would it manage the situation mentioned in question 2(only applicable if JVM allocates memory multiple times to the same method).

JVM 是否会在 myMethod 执行完成后立即释放分配给 myMethod 的内存,如果是这样,它将如何管理问题 2 中提到的情况(仅适用于 JVM 多次为同一方法分配内存的情况)。

Stack frame created for myMethodwill be removed from stack memory, so all the memory created for local variables will be cleaned but this doesn't mean that JVM will clean up the memory allocated in "Permanent Generation" for the class those object you have created in myMethod

为其创建的堆栈帧myMethod将从堆栈内存中删除,因此将为局部变量创建的所有内存都将被清理,但这并不意味着 JVM 将清理在“永久代”中为您创建的那些对象的类分配的内存myMethod

What would have been the case, if I had only declared s and did not initialize it, would JVM still allocate memory to all the methods of java.lang.String class, if so, why?

会是什么情况,如果我只声明了s而不初始化它,JVM还会为java.lang.String类的所有方法分配内存,如果是,为什么?

Specifically talking about Stringclass, JVM would have allocated space for Stringin "Permanent Generation" way too early, while JVM is launched and whether you initialize your String variable or not, it doesn't matter from "Permanent Generation" perspective.

具体说到String类,JVM 会String过早地以“永久代”的方式为“永久代”分配空间,而当 JVM 启动时,无论您是否初始化 String 变量,从“永久代”的角度来看都无关紧要。

Talking about other user-defined classes, JVM would load the class and allocate memory in "Permanent Generation" as soon as you define the class, again even if you do not create an object of the class, memory is allocated in "Permanent Generation" (non-heap area) and when you create an object of the class then memory is allocated in "Eden Space" (heap area).

说到其他用户定义的类,JVM会在定义类后立即加载类并在“永久代”中分配内存,同样即使您不创建类的对象,内存也会在“永久代”中分配(非堆区),当您创建类的对象时,内存将分配在“伊甸园空间”(堆区)中。



Sources of above information and further reading:

以上信息来源及进一步阅读:

回答by Ravindra HV

Since the arsy's accepted answer and hagrawal's answer's are clear, just want to elaborate on the fourth question :

由于arsy的接受答案和hagrawal的答案很清楚,只想详细说明第四个问题:

What would have been the case, if I had only declared s and did not initialize it, would JVM still allocate memory to all the methods of java.lang.String class,if so,why?

会是什么情况,如果我只声明了s而不初始化它,JVM还会为java.lang.String类的所有方法分配内存,如果是,为什么?

Basically while its true that the class data - that has the fields and methods information - is stored in the permanent-generation (meta-space from JDK-8 onwards), it is important to note that its the objects within the java.lang.String class (such as the char[] which holds all the character information for that string) for which data is allocated on the heap.

基本上,虽然具有字段和方法信息的类数据确实存储在永久代(JDK-8 以后的元空间)中,但重要的是要注意它是 java.lang 中的对象。在堆上为其分配数据的字符串类(例如保存该字符串的所有字符信息的 char[])。

This does not happen until either a new string object is created - either using the 'new' keyword or by creating a new string literal (Eg: "helloworld").

在创建新的字符串对象之前不会发生这种情况 - 使用“new”关键字或创建新的字符串文字(例如:“helloworld”)。