Adi*_*lai 19 java memory memory-management heap-memory stack-memory
我想知道如何在以下程序中分配内存:
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!";
}
}
Run Code Online (Sandbox Code Playgroud)
在上图中,堆栈存储器中的内存,obj和s实际上是对它们放置在堆内存中的" 实际对象 " 的引用.
以下是我想到的一系列问题:
MemoryClass
内部对象myMethod
,JVM会在堆栈内存中再次为相同的方法分配内存吗?myMethod
是否会在执行完成后立即释放分配的内存,如果是,它将如何管理问题2中提到的情况(仅当JVM多次为同一方法分配内存时才适用).java.lang.String
类的方法分配内存,如果是这样,为什么呢?arc*_*rcy 19
存储方法在哪里?
它们存储在String类对象中; 它是在程序中首次引用String时由ClassLoader对象加载的对象.我读到这篇文章时所存在的JVM的所有实现都从未在类对象加载后释放内存.它在堆上.
如果我在myMethod中创建了MemoryClass的另一个对象,那么JVM会在堆栈内存中再次为相同的方法分配内存吗?
不,对象的方法和数据是分开保存的,特别是因为JVM永远不需要多个方法副本.
JVM在执行完成后是否会释放分配给myMethod的内存,如果是这样,它将如何管理问题2中提到的情况(仅当JVM将内存多次分配给同一方法时才适用).
不,Java通常不会"立即释放存储在堆上的内容".这会使事情运行得太慢.它只在垃圾收集器运行时释放内存,并且只有在运行垃圾收集器的算法决定它是时候时它才会这样做.
如果我只声明了s并且没有初始化它,那么JVM仍会为java.lang.String类的所有方法分配内存,如果是这样,为什么呢?
这取决于我认为的JVM实现,也许还有编译器.如果你声明一个变量并且从不使用它,那么编译器很可能(并且很常见)注意到它没有用处并且没有将它放入类文件中.如果它不在类文件中,它永远不会被引用,因此它及其方法不会被加载等.如果编译器无论如何都将它放入但它从未被引用,那么ClassLoader将没有任何理由加载它,但我是否会加载或不加载我有点模糊.可能依赖于JVM实现; 它是否加载了东西,因为有类的变量或只有它们被引用?有多少ClassLoader算法可以在4位数PIN码头上跳舞?
我鼓励您阅读有关JVM和ClassLoaders等内容; 你会通过阅读它的工作原理来获得更多,而不是用你能想到的例子来嘲笑它.
首先要做的事情是:我假设你的问题在阅读完这篇文章之后就出现了(因为在那里我看到的图表与你的图表非常相似)所以我不会引用或突出那里提到的任何一点,并会尝试回答用你在帖子中不那么明显的要点提问.
阅读所有问题,我的印象是你很清楚如何在堆栈和堆中分配内存,但对类的元数据有疑问,即在内存中的哪些位置,类的方法将被存储以及如何回收它们.那么,首先让我尝试解释JVM内存区域:
让我首先介绍这两个描绘JVM内存区域的图:
现在,从上面的图表中可以清楚地看到JVM内存的树形结构,我将尝试对它进行修改(@Adit:请注意,与您有关的区域是PermGen Space或非堆内存的永久生成空间) .
堆内存是运行时数据区,Java VM从中为所有类实例和数组分配内存.堆可以是固定的或可变的大小.垃圾收集器是一个自动内存管理系统,可回收对象的堆内存.
年轻代是创建所有新对象的地方.当年轻一代被填满时,进行垃圾收集.此垃圾收集称为Minor GC.Young Generation分为以下两部分
Eden space:最初为大多数对象分配内存的池.
幸存者空间:包含在伊甸园空间垃圾收集中幸存下来的对象的池.
旧生成内存包含多轮次要GC后长寿和存活的对象.通常垃圾收集在Old Generation内存中完成时执行.旧一代垃圾收集称为主要GC,通常需要更长的时间.老一代包含以下部分:
终身空间:包含在幸存者空间中存在一段时间的物体的池.
非堆内存包括在Java VM的内部处理或优化所需的所有线程和内存之间共享的方法区域.它存储每类结构,例如运行时常量池,字段和方法数据,以及方法和构造函数的代码.方法区域在逻辑上是堆的一部分,但是根据实现,Java VM可能不会垃圾收集或压缩它.与堆存储器一样,方法区域可以是固定的或可变的大小.方法区域的内存不需要是连续的.
该池包含虚拟机本身的所有反射数据,例如类和方法对象.对于使用类数据共享的Java VM,这一代分为只读和读写区域.
HotSpot Java VM还包括代码缓存,其中包含用于编译和存储本机代码的内存.
存储方法在哪里?
非堆内存 - >永久生成
如果我在myMethod中创建了MemoryClass的另一个对象,那么JVM会在堆栈内存中再次为相同的方法分配内存吗?
堆栈内存只包含局部变量,因此新的ORV(对象引用变量)MemoryClass
仍将在堆栈帧中创建myMethod
,但JVM不会MemoryClass
在"永久生成" 中再次加载所有方法,元数据等.
JVM只加载一次类,当它加载类时,则在该类的"永久生成"上分配空间,并且在JVM加载类时只发生一次.
JVM在执行完成后是否会释放分配给myMethod的内存,如果是这样,它将如何管理问题2中提到的情况(仅当JVM将内存多次分配给同一方法时才适用).
创建的堆栈帧myMethod
将从堆栈内存中删除,因此将清除为局部变量创建的所有内存,但这并不意味着JVM将清除在"永久生成"中为您创建的那些对象的类分配的内存myMethod
如果我只声明了s并且没有初始化它,那么JVM仍会为java.lang.String类的所有方法分配内存,如果是这样,为什么呢?
特别是在谈论String
类时,JVM会String
过早地以"永久生成"方式分配空间,而JVM启动时无论是否初始化String变量,从"永久生成"角度来看都无关紧要.
谈到其他用户定义的类,JVM会在您定义类时加载类并在"永久生成"中分配内存,即使您不创建类的对象,内存也会在"永久生成"中分配(非堆区域),当您创建类的对象时,内存将在"Eden Space"(堆区域)中分配.
归档时间: |
|
查看次数: |
10451 次 |
最近记录: |