文章目录

  • 一、概述
  • 二、各个区域
    • 1.程序计数器
    • 2.虚拟机栈
    • 3.本地方法栈
    • 4.直接内存
    • 5.方法区
    • 6.运行时常量池
    • 7.堆
  • 三、版本更新
  • 四、相关问题
    • 1、什么是字面量和符号引用?
    • 2、方法区中除了运行时常量池,还有什么?
  • 五、参考

一、概述

    了解JAVA的内存区域是学习JVM第一步,只有懂得了各个区域的工作原理、服务对象以及其中可能存在的问题,才能为日后的JVM调优、内存溢出排错等问题提供帮助。
    根据《虚拟机规范》第二版规定,JVM管理的内存将包含以下几个运行时数据区域:

二、各个区域

    这一部分的阐述是基于JDK1.6,JDK1.7和1.8的改动会在下一部分进行讲解。

1.程序计数器

    当前线程字节码运行的行号指示器,通过程序计数器实现分支、循环、跳转、异常处理、线程恢复等基础功能。这是唯一不会发生内存溢出的区域。

2.虚拟机栈

    每一个方法的执行都会创建一个栈帧,用于存储局部变量表、方法出口、动态链接、操作栈等信息。每一个方法从执行到结束都对应了一个栈帧从虚拟机栈入栈到出栈的过程。
    局部变量表:存放了编译器可知的各种基础数据类型(boolean、byte、char、short、int、float、long、double),对象应用(reference类型,代表对象的句柄或者指向对象起始地址的引用指针 ),和returnAddress(指向了一条字节码指令的地址)。局部变量表所需的空间是编译期间已经确定,在运行期间不会改变大小 。
    动态链接:每一个栈帧都包含了当前方法指向运行时常量池中的符号引用以支持动态链接。这些符号引用在运行时转化为直接引用。
    操作栈:每一个栈帧都包含了一个先进后出栈,称为操作数栈。操作数栈是方法调用和执行的空间,通过弹栈/压栈的形式来操作数据。JVM提供了将局部变量或常量加载到操作数栈的字节码指令,用这些指令将参与运算的值压入操作数栈,然后弹出这些值,进行运算,将结果压回操作数栈。
    方法返回地址:方法执行后下一步指令的地址,方法正常退出时,程序计数器的值可以作为返回地址;异常退出时,返回地址要通过异常处理器决定。

3.本地方法栈

    为虚拟机使用到的native方法服务。

4.直接内存

    在JDK1.4后引入了NIO,一种基于通道channel和缓冲区buffer的I/O方式,它可以使用native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,这样可以避免在java堆和native堆中来回复制数据,在某些场景显著提高性能

5.方法区

    存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,也称为非堆(Non-Heap)。该区域很少出现垃圾回收,回收目标主要是针对常量池的回收和对类型的卸载。

6.运行时常量池

    运行时常量池是方法区的一部分,用于存放多种类型的常量,范围是从编译期已知的字面量到必须在编译期解析的方法和字段引用。
    String.intern()方法可用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。如果不存在,则在该字符串放入常量池中。
    对于直接做+运算的两个字符串(字面量)常量,并不会放入字符串常量池中,而是直接把运算后的结果放入字符串常量池中。(String s = “abc”+ “def”, 会直接生成“abcdef"字符串常量 而不把 “abc” "def"放进常量池)
    对于先声明的字符串字面量常量,会放入字符串常量池,但是若使用字面量的引用进行运算就不会把运算后的结果放入字符串常量池中了(String s = new String(“abc”) + new String(“def”),在构造过程中不会生成“abcdef"字符串常量)
    字符串常量池:在JDK1.7之前,还在运行时常量池;在JDK1.7之后,移到堆中,存储字符串常量和字符串引用

7.堆

    用于存放对象实例,是垃圾收集器的主要工作区域。Java堆分为新生代和老年代,其中新生代还分为Eden区、From Survior区和To Survior区。新生代和老年代的默认比例是1:2。为了更好地回收和分配内存,线程共享的堆还划分出了多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。

三、版本更新

    引用JDK1.7和JDK1.8的内存模型比较这篇博客的一个回答:

在JDK1.7之前,运行时常量池、字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代。
在JDK1.7,字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)

    JDK1.8内存模型:

四、相关问题

1、什么是字面量和符号引用?

    字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
    符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。

2、方法区中除了运行时常量池,还有什么?

    class常量池:我们写的每一个Java类被编译后,就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References);
    字符串常量池:在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,放在了StringTable上。
    在JDK6.0中,StringTable的长度是固定的,长度就是1009,因此如果放入String Pool中的String非常多,就会造成hash冲突,导致链表过长,当调用String#intern()时会需要到链表上一个一个找,从而导致性能大幅度下降;可以存放字符串。
    在JDK7.0中,StringTable的长度可以通过参数-XX:StringTableSize指定,可以存放字符串以及放于堆内的字符串对象的引用。

五、参考

Java虚拟机栈之操作数栈
JVM虚拟机规范官方文档
JDK1.7和JDK1.8的内存模型比较
Java中的常量池(字符串常量池、class常量池和运行时常量池)
《深入了解Java虚拟机:JVM高级特性与最佳实践》书籍

深入了解JVM之内存区域(一)相关推荐

  1. JVM的内存区域划分(转)

    原文链接:JVM的内存区域划分 JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内 ...

  2. java内存区_基于jvm java内存区域的介绍

    jvm虚拟机在运行时需要用到的内存区域.广泛一点就是堆和栈,其实不然,堆和栈只是相对比较笼统的说法,真正区分有如下几个 先上图一: 总的就是 java的内存模型 内存模型又分堆内存(heap)和方法区 ...

  3. JVM的内存区域划分

            JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的 ...

  4. 第1篇--基于jdk7和jdk8分析 JVM的内存区域

     基于jdk7和jdk8分析 JVM的内存区域 目录 前言 1.什么是JVM 2.JRE/JDK/JVM是什么关系 3.JVM执行程序的过程 4. JVM的生命周期 5.JVM垃圾回收 一.运行时数据 ...

  5. Java必突-JVM知识专题(一): Java代码是如何跑起来的+类加载到使用的过程+类从加载到使用核心阶段(类初始化)+类加载的层级结构+什么是JVM的内存区域划分?Java虚拟机栈、Java堆内存

    前言: 该章节知识点梳理:本文主要是入门和了解jvm,不做深入 1.Java代码是如何运行起来的? 2.类加载到使用的过程? 3.验证准备和初始化的过程? 4.类从加载到使用核心阶段:初始化.类加载器 ...

  6. JVM的内存区域和垃圾回收机制

    JVM的内存区域 java 虚拟机在执行java程序的过程中,会把它管理的内存划分为若干那个内存区域,分为以下几种 程序计数器 程序计数器是一个较小的内存空间,他可以看做当前线程所执行的字节码的行号指 ...

  7. java内存四大区,jvm基础-内存区域

    1.运行时数据区 java虚拟机在执行java程序的过程中会爸它所管理的内存分为若干个不同的数据区域 jvm内存主要分为堆.程序计数器.方法区.虚拟机栈喝本地方法栈,直接内存等. java方法的运行和 ...

  8. 深入理解JVM的内存区域划分

    一.首先我们先熟悉一下JVM 1. 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计 ...

  9. JVM Java内存区域 与 内存溢出 (系列号1)

    运行时数据区域 运行时的数据区域,就是JVM管理的内存区域.JVM 运行程序的时候,管理着运行时的内存(一般以静态的 main 方法进入本类的运行时数据区,几乎所有Java程序都是从此开始,也就是说这 ...

  10. JVM各内存区域存放内容

    一.方法区存放内容: 1.类的全限定名(类的全路径名). 2.类的直接超类的权全限定名(如果这个类是Object,则它没有超类). 3.类的类型(类或接口). 4.类的访问修饰符,public,abs ...

最新文章

  1. 因主机名更改造成oracle控制台登录错误:ora-12545,ora-12541
  2. server 2008 配置php mysql_Win2008 Server配置PHP环境
  3. 分块查询 缓解内存开销
  4. 写一个函数,输入int型,返回整数逆序后的字符串
  5. MYSQL中有时候不得不使用replace()去掉特殊字符,写在这里备用一下
  6. bsp模型适用于图计算_【论文解读】目标检测之RFBnet模型
  7. spark2.0配合hive0.13.1使用问题处理
  8. 三方协议接收节点不存在_【花开法务】没有保密协议是否意味着员工不存在保密义务?...
  9. 作业帮:字符串反转(头部插入)
  10. 字典的定义、字典的特性(成员操作符)
  11. 摩托android one手机图片,Motorola One都说外观像iPhone,但实际却不一样!
  12. 【tensorRT文档翻译】7. Working With Dynamic Shapes
  13. PHP 使用 ZipArchive 将文件打包成 zip
  14. 羿的后人证明上古历史不是神话
  15. oracle中表为啥会死锁,Oracle数据表中的死锁情况解决方法
  16. 数字电路与逻辑设计——组合逻辑应用技巧篇
  17. Java阶段三:基础项目—家庭记录收支程序
  18. 衡量公司盈利能力的重要指标-净资产收益率
  19. 接受自己平庸真的很难吗?你知道163邮箱登陆界面是什么吗?
  20. 快手如何运营才能快速涨粉?

热门文章

  1. frameset和frame的使用方法
  2. Win10下的WSL(Linux子系统)开发环境搭建(PHP+Nginx+Mysql+Composer)
  3. SpringMVC 406
  4. mysql如何查看事务日记_Mysql事务和Mysql 日志
  5. 个人ip如何运营?如何打造自己的个人ip?具体好处有哪些?
  6. 银河系召唤“四有青年”,宇宙原力即将觉醒
  7. Android studio3.6.3的jdk版本设置在哪里?
  8. 三维重建——孔洞填补算法
  9. 读论文 Automatic generation and detection of highly reliable fiducial markersnunder occlusion
  10. ar vr mr 计算机技术,VR技术是什么?AR、MR又是什么?