• 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. 最通俗易懂的 Redis 架构模式详解

    前言 话说有一名意大利程序员,在 2004 年到 2006 年间主要做嵌入式工作,之后接触了 Web,2007 年和朋友共同创建了一个网站,并为了解决这个网站的负载问题(为了避免 MySQL 的低性能 ...

  2. 用于测试XmlAnalyzer 1.00版的八个测试用例

    XmlAnalyzer 工程目的:将XML的属性和子节点按字母序排列,然后整形输出: 08. 原文=<project xmlns="http://maven.apache.org/PO ...

  3. 在CentOs7上yum安装redis

    在开始安装步骤之前,先把我的CentOs和redis版本号列出来: # 系统/软件 版本号 1 CentOS7 CentOS Linux release 7.2.1511 (Core) 2 redis ...

  4. 原生JDK网络编程- NIO之Reactor模式

    “反应”器名字中”反应“的由来: “反应”即“倒置”,“控制逆转”,具体事件处理程序不调用反应器,而向反应器注册一个事件处理器,表示自己对某些事件感兴趣,有时间来了,具体事件处理程序通过事件处理器对某 ...

  5. leetcode刷题-73矩阵置零

    题目 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [  [1,1,1],  [1,0,1],  [1,1,1]]输出: ...

  6. SpringMVC-Controller&RestFul

    Controller与RestFul 目录 Controller与RestFul 1. Controller 1. 控制器Controller 2. 利用接口定义控制器 1. 实现Controller ...

  7. mac如何安装YaPi

    首先介绍一下YaPi是干什么的. 帮助开发者轻松创建.发布.维护 API,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理.免费 ...

  8. 说说XcodeLLDB调试的那些事儿

    使用场景之一,接收他人的项目,快速理清其层次结构,可以打标识符断点,如下图 每一个VC,都加了个在viewDidLoad方法处的断点,这样运行程序时,逐步断点,便可以理清层次, 但是,需要手动不断的继 ...

  9. [剑指Offer]55-题目一:二叉树的深度 题目二:平衡二叉树

    题目一 题目 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 题解 递归. 代码 class TreeNode { int v ...

  10. [程序员代码面试指南]栈和队列-最大值减去最小值 小于或等于num 的子数组的数量(单调队列)

    题目 给定数组arr和整数num,求数组的子数组中有多少个的满足"最大值减去最小值<=num". 解题思路 分析题目,有结论: 如果数组arr[i...j]满足条件,则它的每 ...