一、JVM简介

JVM,即Java虚拟机(Java Virtual Machine),一种能够运行Java bytecode的虚拟机,是Java实现跨平台的基础。

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

二、JVM分区

Java虚拟机在执行Java程序的过程中,会把它管辖的内存划分为若干个不同的数据区域。如下图所示:

(1)程序计数器

程序计数器(Program Counter Register):程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。

如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是一个本地(native,由C语言编写完成)方法,则计数器的值为Undefined,由于程序计数器只是记录当前指令地址,所以不存在内存溢出的情况,因此,程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。

(2)虚拟机栈

虚拟机栈(JVM Stack):一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame),栈帧中存储的有局部变量表、操作栈、动态链接、方法出口等,当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈。

局部变量表中存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等。在局部变量表中,只有long和double类型会占用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。

虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足,此时,会抛出OutOfMemoryError(内存溢出)。

每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的

(3)本地方法栈

本地方法栈(Native Method Statck):本地方法栈在作用、运行机制、异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。

本地方法栈也是线程私有的

(4)堆区

堆区(Heap):堆区是理解Java GC机制最重要的区域,没有之一。在JVM所管理的内存中,堆区是最大的一块,堆区也是Java GC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区的存在是为了存储对象实例,原则上讲,所有的对象都在堆区上分配内存(不过现代技术里,也不是这么绝对的,也有栈上直接分配的)。

一般的,根据Java虚拟机规范规定,堆内存需要在逻辑上是连续的(在物理上不需要),在实现时,可以是固定大小的,也可以是可扩展的,目前主流的虚拟机都是可扩展的。如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError异常。

(5)方法区

方法区(Method Area):在Java虚拟机规范中,将方法区作为堆的一个逻辑部分来对待,但事实上,方法区并不是堆(Non-Heap);另外,不少人的博客中,将Java GC的分代收集机制分为3个代:青年代,老年代,永久代,这些作者将方法区定义为“永久代”,这是因为,对于之前的HotSpot Java虚拟机的实现方式中,将分代收集的思想扩展到了方法区,并将方法区设计成了永久代。不过,除HotSpot之外的多数虚拟机,并不将方法区当做永久代,HotSpot本身,也计划取消永久代。本文中,由于笔者主要使用Oracle JDK6.0,因此仍将使用永久代一词。

方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等

方法区在物理上也不需要是连续的,可以选择固定大小或可扩展大小,并且方法区比堆还多了一个限制:可以选择是否执行垃圾收集。一般的,方法区上执行的垃圾收集是很少的,这也是方法区被称为永久代的原因之一(HotSpot),但这也不代表着在方法区上完全没有垃圾收集,其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。

在方法区上进行垃圾收集,条件苛刻而且相当困难,效果也不令人满意,所以一般不做太多考虑,可以留作以后进一步深入研究时使用。

在方法区上定义了OutOfMemoryError异常,在内存不足时抛出。


运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用(符号引用就是编码是用字符串表示某个变量、接口的位置,直接引用就是根据符号引用翻译出来的地址,将在类链接阶段完成翻译);运行时常量池除了存储编译期常量外,也可以存储在运行时间产生的常量(比如String类的intern()方法,作用是String维护了一个常量池,如果调用的字符“abc”已经在常量池中,则返回池中的字符串地址,否则,新建一个常量加入池中,并返回地址)。

(6)直接内存

直接内存(Direct Memory):直接内存并不是JVM管理的内存,可以这样理解,直接内存,就是JVM以外的机器内存,比如,你有4G的内存,JVM占用了1G,则其余的3G就是直接内存,JDK中有一种基于通道(Channel)和缓冲区 (Buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用存储在JVM堆中的DirectByteBuffer来引用。 由于直接内存收到本机器内存的限制,所以也可能出现OutOfMemoryError的异常。

参考资料:https://segmentfault.com/a/1190000002579346

JVM(1)——JVM内存分区相关推荐

  1. JVM运行时内存分区

    什么是JVM?JVM概述--初识JVM(类加载器,垃圾回收器,执行引擎) 上一篇博客我们对jvm以及它的三个"部件"有了初步的认识,这一篇我们探讨一下源码经过编译.加载后这些数据被 ...

  2. 区分-JVM内存分区和Java内存模型(Java Memory Model)

    也是最近被问到了Java内存模型,学识浅薄,一直以为内存分区和内存模型是一个东西,现在做一下笔记整理一下以区分和学习这两个概念及其延伸的一些知识点. 开门见山 解决问题 JVM内存分区具体指的是JVM ...

  3. 什么是JVM?JVM概述——初识JVM(类加载器,垃圾回收器,执行引擎)

    此篇文章属于作者初识之后的概述总结,谈论的层面很浅,大佬勿喷. 目录 类加载器 内存管理器(垃圾回收器) 执行引擎 JVM全称是Java Virtual Machine,意为java虚拟机,所以要了解 ...

  4. jvm内存分区和TLAB

    JVM回顾 JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区域(runtime data area) 运行时数据区域 Java虚拟机在 ...

  5. JVM:查看java内存情况命令

    2019独角兽企业重金招聘Python工程师标准>>> jmap (linux下特有,也是很常用的一个命令) 观察运行中的jvm物理内存的占用情况. 参数如下: -heap :打印j ...

  6. JVM初探:内存分配、GC原理与垃圾收集器

    JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念上可简单认为new时分配外, 我们着重介绍后面的3个步骤: I. ...

  7. jvm 堆外内存_一图解千愁,jvm内存从来没有这么简单过!

    原创:小姐姐味道,欢迎分享,转载请保留出处. 看到这张图的同学,千万不要到处分享.我们仅限于小范围讨论,因为这张图威力很大,是我花了10年时间才画出来的! 了解了这张图,会让你对JVM内存的划分有更深 ...

  8. <JVM笔记:内存与垃圾回收>13-垃圾回收器

    13. 垃圾回收器 13.1. GC 分类与性能指标 13.1.1. 垃圾回收器概述 13.1.2. 垃圾收集器分类 13.1.3. 评估 GC 的性能指标 13.2. 不同的垃圾回收器概述 13.2 ...

  9. JVM上篇:内存与垃圾回收篇十四--垃圾回收器

    JVM上篇:内存与垃圾回收篇十四–垃圾回收器 1. GC分类与新能指标 1.1 垃圾回收器概述 垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商.不同版本的JVM来实现. 由于JDK的版本处于高 ...

最新文章

  1. vim的简单介绍与使用
  2. GCC编译器选项及优化提示
  3. Oracle中较长number型数值的科学计数显示问题
  4. 24 FI配置-财务会计-允许负值记账
  5. nginx开发(二)配置mp4文件在线播放
  6. iOS开发-面试总结(十五)
  7. Yii2框架之旅(六)
  8. yum是什么?(linux命令)
  9. Android 屏幕旋转的多种状态
  10. VS自带工具:dumpbin的使用查看Lib,dll等
  11. 基于Dx11写一个自己的游戏引擎--1
  12. 从gitlab上down下来的项目Django页面加载不出来
  13. 从零搭建Angular10项目
  14. 三星s3 android8.0,三星最新安卓8.0升级计划:这款老机子有戏
  15. WASC Distributed Open Proxy Honeypots
  16. 即时通讯环信IM的集成使用
  17. (25):SPA单页面的理解
  18. csgo调出参数_CSGO参数设定 参数大全汇总
  19. 谷歌胜诉甲骨文,安卓清白还是代码抄袭无罪?
  20. 12306订票助手.NET

热门文章

  1. 如何快速学习使用mybatis以及总结
  2. layui 数字步进器_图解全新奔驰S级:从“传统豪华”向“数字豪华”转型
  3. php 判断update返回为0_PHP进行数据库更新update操作,返回状态
  4. springboot springcloud区别_SpringCloud微服务全家桶-第一篇!为什么要用微服务
  5. 安卓手机运行python程序的软件-安卓手机定时运行python脚本
  6. 清华姚班毕业生不配自信?张昆玮在豆瓣征女友,却被网友群嘲......
  7. 10张让你大脑崩溃的图,敢接受挑战吗?
  8. 不得了,日本出版社竟是这样吸引死宅学编程的
  9. 程序员吐槽_产品经理吐槽大会,程序员勿入
  10. Java开发和嵌入式开发该如何选择