java中的堆栈内存和堆内存(JVM内存模型)
Java 1中的堆内存和堆栈内存的详细说明以及Java 2中的堆内存和堆栈内存的详细说明都粗略地解释了堆栈内存和堆内存之间的区别,以及代码中的哪些变量存储在堆中,并且它们存储在堆栈中。内存中的堆和堆栈是什么?它详细描述了内存中程序的模型。堆和栈是从可执行文件(ELF)格式的编译中引入的,主要是C / C ++语言。解释更加清晰,参考文献也得到了比较。坚强。
实际上,对于Java语言,编译文件是中间字节代码,不能由操作系统直接执行,而需要由JVM解释和执行。对应于C / C ++,要了解Java的堆栈内存和堆内存,您应该从JVM内存模型开始(请参阅深入了解JVM内存模型(jmm)和GC)。
一、 Java内存模型
java程序内存的分配是在JVM虚拟机内存分配机制下完成的。
Java内存模型(Java Memory Model,JMM)是一种内存模型规范,它屏蔽了各种硬件和操作系统的访问差异,并确保Java程序可以在各种平台下访问内存。确保结果一致的机制和规范。
根据Java虚拟机规范,由Java虚拟机管理的内存将分为以下五个区域。

1.程序计数器
程序计数器寄存器是一个很小的存储空间,可以视为当前线程执行的字节码的行号指示符。在虚拟机的概念模型(仅概念模型中,可以以某些更有效的方式实现各种虚拟机),字节码解释器通过更改此计数器的值以选择要执行的下一个计数器来工作。字节码指令,分支,循环,跳转,异常处理和线程恢复都需要依靠此计数器来完成。
Java虚拟机的多线程是通过依次程之间切换并分配处理器执行时间来实现的。也就是说,处理器内核只能同时执行一个线程,而处理器不能切换线程。记录上一个线程执行的位置,因此为了能够在切换线程后返回到原始位置,每个线程都需要有自己的独立程序计数器。
功能:

2. Java堆栈(虚拟机堆栈)(请参阅JVM系列-内存区域-Java虚拟机堆栈(三)))
Java虚拟机的堆栈中的unit元素是堆栈框架。在每个线程中调用相同的方法或不同的方法将创建不同的堆栈框架。在运行线程中,仅当前堆栈框架有效(Java虚拟机堆栈中的顶部堆栈框架),并且与当前堆栈框架关联的方法称为当前方法。每次调用新方法时,与被调用方法相对应的堆栈框架将放在堆栈的顶部(放入堆栈),该堆栈框架将成为新的当前堆栈框架。当一种方法完成并退出时,与此方法相对应的堆栈帧也会被破坏(弹出)。
局部变量表,操作数堆栈,动态链接,方法返回地址和其他信息存储在每个堆栈帧中。
3.本机方法堆栈
本机方法栈(本机方法栈)和Java虚拟机栈起着非常相似的作用。区别在于,虚拟机堆栈为虚拟机提供服务以执行Java方法(即字节码),而本机方法堆栈则为虚拟机使用的本机方法提供服务。本地方法堆栈中方法的语言,用法和数据结构在虚拟机规范中不是强制性的,因此特定的虚拟机可以自由地实现它。
导航方法是Java通过JNI直接调用本地C / C ++库。可以认为Native方法等效于C / C ++向Java公开的接口。 Java通过调用此接口来调用C / C ++方法。当线程调用Java方法时,虚拟机将创建一个堆栈框架并将其压入Java虚拟机堆栈。但是,当虚拟机调用本机方法时,它将使Java虚拟机堆栈保持不变,并且不会将新的堆栈框架推入Java虚拟机堆栈中。虚拟机只是简单地动态连接并直接调用指定的本机方法。
4.堆(请参阅JVM系列-内存区域-Java堆(五)))
Java堆是Java虚拟机管理的最大内存,也称为“ GC堆”。这是所有线程共享的内存区域,是在虚拟机启动时创建的。
唯一的用途是存储对象实例和数组(JDK7已将字符串常量池和类静态变量移至Java堆)。几乎所有对象实例都将存储在堆中并进行分配。随着JIT编译器的发展,诸如转义分析,堆栈分配和标量替换之类的优化技术已导致并非所有对象都分配在堆上。
Java堆是由垃圾收集器管理的主要区域。堆内存分为年轻人和。年轻人分为三个区域:伊甸园,幸存者和幸存者。
根据Java虚拟机规范,Java堆可以在物理上不连续的内存空间中,只要它在逻辑上是连续的(就像我们的磁盘空间一样)即可。在实现中,可以将其实现为固定大小或可扩展,但是当前的主流虚拟机是根据可伸缩性(由-Xmx和-Xms控制)实现的。
5.方法区域()
方法区,就像Java堆一样,是所有线程共享的内存区。
在JDK7(永久生成)之前,它用于存储虚拟机已加载的数据,例如类信息,常量,字符串常量,类静态变量以及由即时编译器编译的代码。
Java虚拟机规范将方法区域描述为堆的逻辑部分,但是它有一个别名,称为非堆(non-Heap,non-heap),目的是将其与Java堆区分开来。
运行时常量池是方法区域的一部分。除了诸如类的版本/字段/方法/接口之类的描述信息之外,类文件中还有一条信息是常量池表,用于存储在编译过程中生成的各种文字和符号引用。内容的这一部分在加载后将类存储在方法区域中的运行时常量池中。也可以在操作期间将新的常量放入池中。开发人员通常在String.intern()方法中使用此功能。
java中大多数包装类的基本类型都实现了常量池技术。这些类是Byte,Short,Integer,Long,Character,Boolean,并且未实现Float和Double类型的包装类。另外,五个整数包装类Byte,Short,Integer,Long和Character仅在对应值在-128和127之间时才可以使用对象池。
在旧版本的jdk中,方法区域也称为永久生成(大小可以通过-XX:PermSize和-XX:MaxPermSize进行调整)。 JDK8完全从HotSpot JVM中删除了永久生成,并删除了其原始数据,并将其迁移到Java Heap或Native Heap(Metaspace),并由另一个称为Metaspace的内存区域代替。
元空间:元空间是HotSpot JVM中方法区域的实现。方法区域主要用于存储类信息,常量池,方法数据,方法代码,符号引用等。元空间的性质类似于永久生成的性质,二者都是方法区域中的实现。 JVM规范。但是,元空间和永久生成之间的最大区别是元空间不在虚拟机中,而是使用本地内存。理论上,元空间的大小取决于32位/ 64位系统的内存大小,并且可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize配置内存大小。
二、 Java中经常提到的堆栈内存和堆内存
我们经常说的堆栈内存和堆内存只是Java内存模型的一部分,这是在编程过程中需要更多注意的部分。
堆栈通常是指堆栈帧中的局部变量表(8种存储类型:字节,短型,整数,长型,浮点型,双精度型,字符型,布尔型和引用,返回地址),它是一块连续的内存该空间用于存储方法参数和方法中定义的局部变量,并存储在编译期间已知的数据类型。局部变量表所需的内存空间是在编译期间分配的。输入方法时,将完全确定该方法需要在堆栈上分配多少局部变量空间,并且局部变量表的大小在该方法运行期间不会更改。
堆通常是指Java内存模型中的堆,用于存储对象实例和数组。几乎所有对象实例都存储在堆中并进行分配。 Java堆是由Java虚拟机管理的最大内存,也称为“ GC堆”,并且是由垃圾收集器管理的主要区域。
三、堆栈内存和堆内存之间的区别(只是容易记住,并不严格)

存储的数据和生命周期
堆栈主要用于存储方法参数,局部变量和对象引用变量。它存储编译期间已知的数据类型(八种基本类型和对象引用(引用类型),returnAddress类型。每个线程将具有一个独立的堆栈空间,堆栈存储器的数据生命周期以该线程的结尾结束。
所有对象实例和数组必须在堆上分配内存。堆中存储的对象由线程共享。当线程结束时,对象实例和数组的生命周期不一定要结束,只有在GC回收之后。
空间大小和局限性
堆栈的内存大小是在编译时确定的。它是一个连续的空间,在运行时不会改变。线程末尾将自动回收堆栈内存。如果请求的堆栈深度大于虚拟机允许的堆栈深度,则JVM将抛出java.lang.StackOverFlowError。
程序运行时动态分配堆内存。它可能是物理上不连续的存储空间。线程运行后,GC将回收它(仅当不再引用该对象或数组时)。如果堆内存中没有可用空间来存储生成的对象,则JVM将抛出java.lang.OutOfMemoryError。
专有或共享
堆栈存储器属于一个线程,并且每个线程都有一个堆栈存储器。存储在其中的变量只能在它所属的线程中看到,也就是说,堆栈存储器可以理解为线程的专用存储器。堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
分配效率
系统自动分配堆栈,速度更快。通常,new分配的堆内存比较慢,并且容易出现内存碎片,但是使用起来最方便。
访问速度(在jvm中可能有所不同)
由于许多CPU具有对堆栈和弹出操作的硬件(指令)支持,因此在堆栈区域中分配/返回内存的速度非常快(相比之下,在堆上分配的速度仅仅是乌龟的速度);特别是函数内部的局部变量可以很容易地与函数的调用/返回绑定,因此几乎所有编译语言都将使用堆栈来管理局部变量(并且将优先使用自由寄存器,因此几乎所有级别的语言可以最快访问本地变量)。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-362678-1.html
默默祝福你
最后笑的好可爱
数十万伊拉克军人