Java 内存模型基本概念

一 根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分

内存模型
栈模型

1、栈:用于存放运行时局部变量(基本数据类型和对象引用)、操作栈、动态链接、方法出口等数据信息。

  • 虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建。
  • 栈帧:栈里面存着的是一种叫“栈帧”(Java方法执行的内存模型)模型,每个方法被执行时都会创建一个栈帧,当方法执行结束后这些变量所占有的内存将会自动释放。
  • 每个线程都有自己独立的栈空间,不共享。
  • 线程栈只存放基本数据类型和对象引用地址。
  • 方法中局部变量在线程栈空间中。
  • 栈的大小可以固定也可以动态扩展。
  • 当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误,不过这个深度范围不是一个恒定的值。

本地方法栈:

  • Native方法服务。在HotSpot虚拟机中和Java虚拟机栈合二为一.
  • 这部分主要与虚拟机用到的 Native 方法相关,一般情况下, Java 应用程序员并不需要关心这部分的内容.
  • PC 寄存器(程序计数器):
  • PC 寄存器,也叫程序计数器。JVM支持多个线程同时运行,每个线程都有自己的程序计数器。倘若当前执行的是 JVM 的方法,则该寄存器中保存- 当前执行指令的地址;倘若执行的是native 方法,则PC寄存器中为空。

2、堆(heap):用于存放对象实例,在虚拟机启动时创建,几乎所有的对象实例都在这里分配内存。堆 是被所有线程共享的一块内存区域,当对象不再使用时,该对象所占用的内存会被释放,该对象被销毁。

  • 这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
  • 堆又分为:新生代、和老年代(还有一个永久代PermGen,存在方法区中)
  • 新生代:Young Generation,主要用来存放新生的对象。
  • 老年代:Old Generation或者称作Tenured Generation,主要存放应用程序声明周期长的内存对象。
  • OutOfMemoryError:当申请不到空间时会抛出 OutOfMemoryError

3、方法区:(Method Area)与Java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、静态数据(static方法和static属性)、常量池(final)等,在虚拟机启动的时候就已经创建,并且在整个程序运行期间都存在。

  • 虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。
  • 运行时常量池:方法区的一部分,用于存放各种字面量(interned strings)(如 字符串常量 和 符号引用(Symbols) 。
  • 方法区内存模型规范的实现 :PermGen 和 Metaspace
  • 永久代PermGen:并非 所有 JVM都存在 PermGen, 在 JDK 8 中 HotSpot PermGen 已经完全移除。
  • 元空间Metaspace: JDK 8 HotSpot 中新增,Metaspace使用的是本地内存,而不是堆内存。
  • JDK 6 之前 字面量(interned strings)(如 字符串常量),符号引用(Symbols) 存在方法区 ( PermGen )中。
  • JDK 8中 HotSpot 字面量(interned strings)(如 字符串常量)由永久代转移到java heap中,符号引用(Symbols)转移到了native heap 。

二 对象访问

Java是面向对象的一种编程语言,那么如何通过引用来访问对象呢?一般有两种方式:
1、通过句柄访问
通过句柄访问
2、直接指针
直接指针

此种方式也是HotSpot虚拟机采用的方式。

三 、内存溢出

在JVM申请内存的过程中,会遇到无法申请到足够内存,从而导致内存溢出的情况。一般有以下几种情况:

  • 虚拟机栈和本地方法栈溢出
    • StackOverflowError: 线程请求的栈深度大于虚拟机所允许的最大深度(循环递归)
    • OutOfMemoryError: 虚拟机在扩展栈是无法申请到足够的内存空间,一般可以通过不停地创建线程引起此种情况
  • Java堆溢出: 当创建大量对象并且对象生命周期都很长的情况下,会引发OutOfMemoryError
  • 运行时常量区溢出:OutOfMemoryError:PermGen space,这里一个典型的例子就是String的intern方法,当大量字符串使用intern时,会触发此内存溢出
  • 方法区溢出:方法区存放Class等元数据信息,如果产生大量的类(使用cglib),那么就会引发此内存溢出,OutOfMemoryError:PermGen space,在使用Hibernate等框架时会容易引起此种情况。

猜你喜欢

转载自blog.csdn.net/wbxx727124/article/details/79241192