重新理解jvm运行时的内存分布(堆栈方法区交互)

Python07

重新理解jvm运行时的内存分布(堆栈方法区交互),第1张

栈堆方法区的交互关系

java栈存储的本地变量表,包括八种数据类型和引用类型,引用类型指向对象的地址,保存在reference,指向java堆,对象类型数据会保存变量名,变量类型,变量值等,这些会存在方法区中去查看(在初始化的时候)。

在java栈中会存放对象实例(s1),但是他对象实例中具体的数据会由java栈中的引用指向java堆中的地址,里面的对象实例数据存放(实例名,实例相关类型,元数据信息。。。。),而静态变量,常量,类加载后的信息等会存放在方法区,在运行时需要调用的时候去方法区取,所以方法区和java堆都是共享的。而java栈时线程独有的数据(包括程序计数器,本地方法栈)。

一个jvm实例,只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件之后,需要把类,方法,常量放到堆内存中,保存所有的引用类型的真实信息,以方便执行器执行。堆内存分为三部分。

(养老区就是老年代)

堆内存 逻辑上 分为三部:新生 +养老 +方法区

eden+survivor+Spaces(元空间或者叫方法区或者Perm)

Perm 永久存储区,是一个常驻内存的区域,用于存放jdk自身携带的Class,Interface的元数据,被装载进此区域的数据是不会被垃圾回收器回收的,只有关闭jvm后才会释放此区域所占用的内存。

如果出现OutOfMemoryReeor: PermGen space 说明java虚拟机堆永久带Perm内存设置不够,一半出现这种情况,都是程序启动加载大量第三方jar呆滞的,

对于HotSpot虚拟机很多开发者习惯将方法区称之为永久代(Parmenent

Gen),永久代是方法区的一个实现,这是不对的,方法区是逻辑上的部分。在jdk7中已经将原本放在永久代的字符串常量池移走了。

常量池( Constant Pool Constant PoolConstant Pool Constant Pool Constant Pool )是方法区的一部分, Class Class文件除了有类的版本、 字段方法、接口等描述信息外,还有一项就是常量池这部分内容将在类加载后进入。

伊甸园区,所有对象刚new出来都会放在这里。

对象分两种:

1.如果是大对象直接分配在Old区。

2.如果禁言了逃逸分析,会在栈上分配。

以上两种都不符合,放入伊甸园区。(Eden区)

看java7中如图:

对比java8

方法区,又称永久代(Permanent Generation),常称为PermGen,位于非堆空间,又称非堆区(Non-Heap space)。方法区是被所有线程共享。所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,此区属于共享区间。 静态变量 + 常量 + 类信息(构造方法/接口定义) + 运行时常量池存 在方法区中 。但是, 实例变量 存在 堆内存 中,和方法区无关。以上,只是逻辑上的定义。在HotSpot中,方法区仅仅只是逻辑上的独立,实际上还是包含在Java堆中,也是就说,方式区在物理上属于Java堆区中的一部分,而永久区(Permanent Generation)就是方法区的实现。

堆:存一个类的引用类型变量;

方法区:java虚拟机在加载.class文件时,将文件读入方法区,静态方法也存在方法区

它俩是不同的内存空间,有不同的用途。

共同点:实在没什么共同点,都是内存中的空间