• JVM 堆中的数据是共享的,是占用内存最大的一块区域。
  • 可以执行字节码的模块叫作执行引擎。
  • 执行引擎在线程切换时怎么恢复?依靠的就是程序计数器。
  • JVM 的内存划分与多线程是息息相关的。像我们程序中运行时用到的栈,以及本地方法栈,它们的维度都是线程。
  • 本地内存包含元数据区和一些直接内存。
  • 本地方法栈是和虚拟机栈非常相似的一个区域,它服务的对象是 native 方法。你甚至可以认为虚拟机栈和本地方法栈是同一个区域,这并不影响我们对 JVM 的了解

Java虚拟机栈(JVM Stacks)

Java 虚拟机栈是基于线程的,每一个线程都有一个栈,哪怕你只有一个 main() 方法,也是以线程的方式运行的。在线程的生命周期中,参与计算的数据会频繁地入栈和出栈,栈的生命周期是和线程一样的。

栈里的每条数据,就是栈帧。在每个 Java 方法被调用的时候,都会创建一个栈帧,并入栈。一旦完成相应的调用,则出栈。所有的栈帧都出栈后,线程也就结束了。每个栈帧,都包含四个区域:

局部变量表

操作数栈

动态连接

返回地址(return address)

因为这种类型只存在于字节码层面,所以我们平常打交道的比较少。对于 JVM 来说,程序就是存储在方法区的字节码指令,而returnAddress 类型的值就是指向特定指令内存地址的指针。

程序计数器(Program Counter)

每一个线程都有他自己的程序计数器

存放指令位置,虚拟机的运行类似于这样的循环:

while(not end){
//取PC中的位置,找到对应位置的指令;
//执行该指令;
//PC++;
}

每一个线程都有一个Program Counter,程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。这里面存的,就是当前线程执行的进度,下面这张图,能够加深对这个过程的理解



程序计数器还存储了当前正在运行的流程,包括正在执行的指令、跳转、分支、循环、异常处理等。

下面这张图,就是使用 javap 命令输出的字节码。大家可以看到在每个 opcode 前面,都有一个序号。就是图中红框中的偏移地址,可以认为它们是程序计数器的内容。

堆 (Heap)

1.理解堆



  • 堆是 JVM 上最大的内存区域,我们申请的几乎所有的对象,都是在这里存储的。我们常说的垃圾回收,操作的对象就是堆
  • 堆空间一般是程序启动时,就申请了,但是并不一定会全部使用
  • 随着对象的频繁创建,堆空间占用的越来越多,就需要不定期的对不再使用的对象进行回收。这个在 Java 中,就叫作 GC(Garbage Collection)

2.创建对象的时候,到底是在堆上分配,还是在栈上分配呢?

这和两个方面有关:对象的类型和在Java 类中存在的位置。

普通对象:JVM如果开启了逃逸分析,满足在栈上分配的条件,就会在栈上分配,如果栈上分配不下,才在堆上创建对象,然后在其他地方使用的其实是它的引用。比如,把这个引用保存在虚拟机栈的局部变量表中。

基本数据类型:每个线程拥有一个虚拟机栈。在方法体内声明了基本数据类型的对象,它就会在栈上直接分配

直接内存

JVM 可以直接访问内核空间的内存(OS管理的内存)

NIO,提高效率,实现零拷贝(Zero Copy)

元空间(Metaspace)

再来看一下这个JVM内存区域划分图

为什么有 Metaspace 区域?它有什么问题?

在 Java 8 之前,生成的 X.class这些类的元数据信息是放在堆上一个叫 Perm 区的内存里面的。更早版本,甚至 String.intern 相关的运行时常量池也放在这里。原来的 Perm 区(又称为永久代)是在堆上的,这个区域有大小限制,而且不会垃圾回收,因此很容易造成 JVM 内存溢出,从而造成 JVM 崩溃。

Perm 区在 Java 8 中已经被彻底废除,取而代之的是 Metaspace。现在的元空间是在非堆上的,这是背景。看下图:

元空间的好处也是它的坏处

好处:使用非堆可以使用操作系统的内存,JVM 不会再出现方法区的内存溢出;

坏处:无限制的使用会造成操作系统的死亡。所以,一般也会使用参数 -XX:MaxMetaspaceSize 来控制大小,如果不设置仅仅会受限于物理内存的大小

方法区(Method Area)

1.8版本之前字符串位于Perm Space。FullGC不会清理

1.8版本之后,字符串常量位于堆,会触发FullGC

我们常说的字符串常量,存放在哪呢?

由于常量池,1.7之前是在Perm永久代里,从1.8开始放到了堆中,我们创建的字符串,将会在堆上分配。

欢迎添加我的个人微信一起探讨

JVM内存布局(又叫Java运行时数据区)的更多相关文章

  1. 深入理解java:1.3.1 JVM内存区域的划分(运行时数据区)

    学习Java GC机制,可以帮助我们在日常工作中 排查各种内存溢出或泄露问题,解决性能瓶颈,达到更高的并发量,写出更高效的程序. 我们将从4个方面学习Java GC机制, 1,内存是如何分配的: 2, ...

  2. Jvm基础(1)-Java运行时数据区

    最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...

  3. 读书笔记-浅析Java运行时数据区

    作为一个 Java 为主语言的程序员,我偶尔也需要 用 C/C++ 写程序,在使用时让我很烦恼的一件事情就是需要对 new 出来的对象进行 delete/free 操作,我老是担心忘了这件事情,从而导 ...

  4. Java 运行时数据区和内存模型

    运行时数据区是指对 JVM 运行过程中涉及到的内存根据功能.目的进行的划分,而内存模型可以理解为对内存进行存取操作的过程定义.总是有人望文生义的将前者描述为 "Java 内存模型" ...

  5. JVM学习笔记一:Java运行时数据区域

    1. 程序计数器 当前线程所执行的字节码的行号指示器. 2. Java虚拟机栈 线程私有,与线程具有相同生命周期.用于存储局部变量表.操作数栈.动态链表.方法出口等信息. 局部变量表存放内容: 基本数 ...

  6. JVM详解(三)——运行时数据区

    一.概述 1.介绍 类比一下:红框就好比内存的运行时数据区,在各自不同的位置放了不同的东西.而厨师就好比执行引擎. 内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的 ...

  7. 【转】Java运行时数据区简介及堆与栈的区别

    理解JVM运行时的数据区是Java编程中的进阶部分.我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机 ...

  8. Java 运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  9. JVM详解(四)——运行时数据区-堆

    一.堆 1.介绍 Java运行程序对应一个进程,一个进程就对应一个JVM实例.一个JVM实例就有一个运行时数据区(Runtime),Runtime里面,就只有一个堆,一个方法区.这里也阐述了,方法区和 ...

  10. Java运行时数据区

    目录 1. 概述 2. Java内存结构 3. 程序计数器 4. Java虚拟机栈 5. 本地方法栈 6. 堆 7. 方法区 8. 运行时常量池 9. 直接内存 10. 总结 1. 概述 作为日常的J ...

随机推荐

  1. Pytest的装饰器——parametrize中ids里包含中文,用例标题显示异常如何解决?

    在使用pytest做测试的过程中,经常会用到pytest.mark.parametrize来对批量生成测试用例,比如 @pytest.mark.parametrize( ['a', 'b', 'exp ...

  2. akka-streams - 从应用角度学习:basic stream parts

    实际上很早就写了一系列关于akka-streams的博客.但那个时候纯粹是为了了解akka而去学习的,主要是从了解akka-streams的原理为出发点.因为akka-streams是akka系列工具 ...

  3. [01] C#网络编程的最佳实践

    网络框架的选择 C++语言里面有asio和libuv等网络库, 可以方便的进行各种高效编程. 但是C#里面, 情况不太一样, C#自带的网络API有多种. 例如: Socket TcpStream(同 ...

  4. 【NOIP2013模拟】太鼓达人

    题目描述 七夕祭上,Vani牵着cl的手,在明亮的灯光和欢乐的气氛中愉快地穿行.这时,在前面忽然出现了一台太鼓达人机台,而在机台前坐着的是刚刚被精英队伍成员XLk.Poet_shy和lydrainbo ...

  5. Linux系统环境基于Docker搭建Mysql数据库服务实战

    开放端口规划: mysql-develop:3407 mysql-test: 3408 mysql-release: 3409 ps: 1.不推荐使用默认端口-3306,建议自定义端口 2.如果采用阿 ...

  6. 终于有人把MYSQL索引讲清楚了

    一什么是索引 索引在MYSQL中也可以称为键,其是存储引擎用于快速查找记录的一种数据结构:这样听起来有点生涩,你可能难以理解:如果给你一本书,你如何能够精确的查找到书中某个章节的具体位置呢?我们肯定是 ...

  7. [LeetCode]96. 不同的二叉搜索树(DP,卡特兰数)

    题目 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ ...

  8. 离线安装Superset 0.37

    上文提到了Superset 0.37的在线安装方式,只需要更新pip,然后pip install就可以了.但是在生产环境中,特别是内网环境中,很多时候是没有外网的,这时候就需要采取离线安装的方式. 本 ...

  9. python中的运动控制函数

    运动控制函数:控制海龟走直线&走曲线 海龟向前行进,海龟走直线,参数d表示行进距离,也可以为负数,单位是像素 根据半径r绘制extent角度的弧形 r : 默认圆心在海龟左侧r 距离的位置 e ...

  10. 4.Strom-可靠性保证