JVM之内存模型(java虚拟机栈,本地方法区栈,方法区,堆,程序计数器)

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

 

 

 

 

 

jvm运行class文件  

class文件中的内容放到jvm的不同地方(数据区)

class文件中到底有多少种数据类型?

对象,常量,静态变量,成员变量,方法,局部变量,父类,*

怎么划分?为什么这样划分

https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

2.5. Run-Time Data Areas   运行时数据区

复制代码
2.5.1. The pc Register   程序技术器
2.5.2. Java Virtual Machine Stacks  java虚拟机栈
2.5.3. Heap         堆
2.5.4. Method Area  方法区
2.5.5. Run-Time Constant Pool 运行时常量池   是方法区的一部分
2.5.6. Native Method Stacks    本地方法区栈

堆-- 对象[普通的成员变量]/数组   ----> new Person() new Student()

Java虚拟机有一个在所有Java虚拟机线程之间共享的堆。堆是为所有类实例和数组分配内存的运行时数据区域。

堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;对象从不显式释放。Java虚拟机假设没有特定类型的自动存储管理系统,可以根据实现者的系统需求选择存储管理技术。堆的大小可以是固定的,也可以根据计算的需要进行扩展,如果不需要更大的堆,则可以收缩。堆的内存不需要是连续的。

Java虚拟机实现可以为程序员或用户提供对堆初始大小的控制,如果可以动态扩展或收缩堆,还可以控制堆的最大和最小大小。

下列异常情况与堆相关:

如果计算需要的堆比自动存储管理系统提供的堆多,则Java虚拟机抛出OutOfMemoryError。

本地方法区栈-

Java虚拟机的实现可以使用传统堆栈(俗称“C堆栈”)来支持本机方法(用Java编程语言以外的语言编写的方法)。本地方法栈的实现也可以使用一个翻译为Java虚拟机的指令集的语言如c . Java虚拟机实现,无法加载本地方法,自己不依赖传统的本地方法栈栈不需要供应。如果提供,通常在创建每个线程时为每个线程分配本机方法堆栈。

该规范允许本机方法堆栈具有固定的大小,或者根据计算的需要动态扩展和收缩。如果本机方法堆栈的大小是固定的,那么在创建该堆栈时可以独立地选择每个本机方法堆栈的大小。

Java虚拟机实现可以为程序员或用户提供对本机方法堆栈初始大小的控制,也可以为可变大小的本机方法堆栈提供对最大和最小方法堆栈大小的控制。

下列异常情况与本机方法堆栈相关:

如果线程中的计算需要比允许的更大的本机方法堆栈,则Java虚拟机将抛出一个StackOverflowError错误。

如果可以动态扩展本机方法堆栈,并且尝试扩展本机方法堆栈,但是没有足够的内存可用,或者没有足够的内存可用来为新线程创建初始本机方法堆栈,则Java虚拟机抛出OutOfMemoryError。

Java虚拟机栈- 局部变量,方法调用和返回(先进后出)

每个Java虚拟机线程都有一个私有的Java虚拟机堆栈,与线程同时创建。Java虚拟机堆栈存储帧(§2.6)。Java虚拟机堆栈类似于C等传统语言的堆栈:它包含局部变量和部分结果,并在方法调用和返回中起作用。因为除了push和pop帧外,Java虚拟机堆栈从来没有被直接操作过,所以可以对帧进行堆分配。Java虚拟机堆栈的内存不需要是连续的。

在Java®虚拟机规范的第一版中,Java虚拟机堆栈被称为Java堆栈。

该规范允许Java虚拟机堆栈具有固定的大小,或者根据计算的需要动态扩展和收缩。如果Java虚拟机堆栈的大小是固定的,则可以在创建该堆栈时独立地选择每个Java虚拟机堆栈的大小。

Java虚拟机实现可以为程序员或用户提供对Java虚拟机堆栈初始大小的控制,在动态扩展或收缩Java虚拟机堆栈的情况下,还可以提供对最大和最小大小的控制。

下列异常情况与Java虚拟机堆栈相关:

如果线程中的计算需要比允许的更大的Java虚拟机堆栈,则Java虚拟机将抛出一个StackOverflowError错误。

如果Java虚拟机栈可以动态地扩展,和扩张是未遂但可以可用内存不足影响扩张,或者内存不足可以创建一个新线程的初始Java虚拟机栈,Java虚拟机抛出一个OutOfMemoryError。

栈先进后出的例子

方法区--类的信息[创建的时间,元数据信息]、全局常量、静态变量、方法和构造函数的代码

Java虚拟机有一个在所有Java虚拟机线程之间共享的方法区域。方法区域类似于常规语言的已编译代码的存储区域,或类似于操作系统进程中的“文本”段。它存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化以及接口初始化中使用的特殊方法(§2.9)。

方法区域是在虚拟机启动时创建的。虽然方法区域在逻辑上是堆的一部分,但简单的实现可能选择不进行垃圾收集或压缩。此规范并不强制要求方法区域的位置或用于管理已编译代码的策略。方法区域可以是固定大小的,也可以根据计算的需要进行扩展,如果不需要更大的方法区域,则可以收缩。方法区域的内存不需要是连续的。

Java虚拟机实现可以为程序员或用户提供对方法区域初始大小的控制,在可变大小方法区域的情况下,还可以提供对最大和最小方法区域大小的控制。

以下是与方法区域相关的异常情况:

如果方法区域中的内存不能满足分配请求,则Java虚拟机抛出OutOfMemoryError。

程序计数器

记录线程运行到哪个位置

Java虚拟机可以同时支持多个线程执行(JLS§17)。每个Java虚拟机线程都有自己的pc(程序计数器)寄存器。在任何时候,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法(§2.6)。如果该方法不是本机的,则pc寄存器包含当前正在执行的Java虚拟机指令的地址。如果线程当前执行的方法是本机的,则Java虚拟机的pc寄存器的值是未定义的。Java虚拟机的pc寄存器足够宽,可以容纳特定平台上的returnAddress或本机指针。

 

 

 

堆会指向方法区,获取对象的数据

 

 

 

 

 

java内存模型中堆和栈的区别

联系:引用对象、数组时,栈里定义变量保存堆中目标的首地址

 

  • 管理方式:栈自动释放,堆需要GC
  • 空间大小:栈比堆小
  • 碎片相关:栈产生的碎片远小于堆
  • 分配方式:栈支持静态和动态分配,而堆仅支持动态分配
  • 效率:栈的效率比堆高

 

总结:

堆和方法区是所有线程共享的,其他的是线程私有的

1、首先在Java中程序员都不可以直接操作堆和栈

2、new创建的对象存在于堆中,局部变量存在于栈中。在堆中定义的对象会在栈中存其的首地址,方便快速访问。

3、栈的存取方式为先进后出,堆为先进先出

4、栈的访问速度快于堆

5、栈的生命周期一般短,用完即释放。堆相对较长,用完不一定释放,由操作系统的内存回收机制决定

posted @ 2020-03-09 14:47  你猜lovlife  阅读(419)  评论(0)    收藏  举报