Java内存模型(Java Memory Model),简称JMM,定义了JVM(Java虚拟机)在计算机内存(RAM)中的工作方式,目的是定义一个一致的、跨平台的内存模型,是隶属于JVM的。

内存模型的组成

在这里插入图片描述

线程私有

Thread Local

私有数据区域其它线程不可见,生命周期随着线程的的启动而创建,线程结束而销毁。

程序计数器

  • 描述

    • 线程执行的字节码行号指示器,通过改变这个计数器来获取下一条执行的指令
      分支、循环、跳转、异常处理和线程恢复等基础功能都需要依赖这个计数器来完成
  • 特点

    • 指向虚拟机字节码指令的位置
      唯一一个不会OOM的区域

虚拟机栈

VM Stack

  • 虚拟机栈生命周期==线程生命周期
    所以对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就over

  • 一个线程中,每调用一个方法创建一个栈帧(Stack Frame)

  • 栈帧结构

    • 局部变量表
      Local Variable Table
    • 操作栈
      Operand Stack
    • 动态连接
      Dynamic Linking
    • 返回地址
      Return Address
    • … …

本地方法栈

Local Method Stack

  • 为本地Native方法服务

线程共享

Thread Shard

Java堆(类实例区)

Objects

  • 存放对象实例,也是垃圾收集器主要的管理区域

  • 区域

    • 新生代

      • eden
      • from survivor
      • to survivor
    • 老年代

方法区(永久代)

Method Area

  • 数据

    • 存储虚拟机加载的类信息

    • 即时编译后的代码

    • 运行时常量池 RCP(Runtime Constant Pool)

      • 直接常量(基本类型、String)

      • 其它类型方法字段的引用

        • 类和接口的全限定名
        • 字段的名称和描述符
        • 方法的名称和描述符
    • 静态变量

  • 特点

    • 垃圾收集器行为很少在此区域发生,主要针对类的卸载、运行时常量池的回收
  • 在java1.8中已移至Matespace区,存储在本地对内存中,不受java堆大小限制,也是为了更好的和JRockit整合
    常量和静态变量移至堆中,其余保持不变,不会再有垃圾回收器扫描元空间

直接内存

Direct Memory

不受JVM GC管理

并不是JVM的一部分,可以使用native函数直接分配堆外内存,然后使用DirectByteBuffer对这块内存的引用进行操作,避免在Java堆和Native之间来回复制数据,在一些场景中可以显著提高性能

总结(干货):

  1. 实例和对象的区别:Class a=new Class();此时的a是实例而不是对象,实例在栈中而对象在堆中,操作实例实际上是间接操作对象。多个实例可以指向一个对象。
  2. 栈中数据与堆中数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中的对象不一定销毁。因为可能其它变量也指向了这个对象,直到所有线程栈中没有变量指向这个对象时,它才销毁,而且不是马上销毁,需要等垃圾回收器扫描时才能销毁。
  3. 类的成员变量在不同对象中各不相同,都有自己的存储空间(在堆的对象中)。而类的方法是该类共享的,只有一套,存储在方法区中,当有对象使用方法时压入栈,方法不使用时不占用内存。
  4. 生命周期:对内存属于java应用程序使用,生命周期与jvm一致;栈内存属于线程私有,生命周期与线程相同
  5. 引用:不论合适何地创建对象,它总是存储在堆内存空间中,并且栈内存包含对它的引用。栈内存空间仅包含方法原始数据类型局部变量和堆空间中对象的引用变量
  6. 二者抛出异常方式:如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常;堆内存不足时将抛出OutOfMemoryError异常

扩展: jdk8中新增的元数据空间

替换了原有的方法区,主要有如下变化:

1. 将方法区中的静态变量、常量池移到了堆中
2. 元空间大小取决于机器的可用内存大小

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐