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

上一篇博客我们对jvm以及它的三个“部件”有了初步的认识,这一篇我们探讨一下源码经过编译、加载后这些数据被jvm分类存储在内存中,根据数据的特性,jvm从逻辑上把内存划分为以下几个区域:方法区、虚拟机栈、本地方法栈、程序计数器、堆。

程序计数器(线程私有)

程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。

如果当前线程正在执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
如果正在执行的是Native方法,这个计数器的值为空。

程序计数器内存区域是唯一一个在jvm规范中没有规定任何OOM(OutOfMemoryError)情况的区域。

程序计数器为什么是线程私有?
由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理器(多核处理器则指的是一个内核)都会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响。

虚拟机栈(线程私有)

虚拟机栈描述的是java方法执行的内存模型:这部分区域主要是用于线程运行方法的区域,此区域属于线程私有的空间,每一个线程创建后都会申请一个自己单独的栈空间,每一个方法执行的同时都会创建一个栈帧用于存储局部变量表(保存着变量的数据)、操作数栈(进行运算时存放数据的空间)、动态链接(指向常量池的引用)、方法出口等信息。每个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。声明周期与线程相同。
下面来模拟一下执行方法时进栈出栈的过程:

执行以下代码

public class JavaStackTest {​public static void main(String[] args) {System.out.println("开始执行main方法");test1();
​}
​public static void  test1(){System.out.println("test1");test2();}
​public static void  test2(){System.out.println("test2");}
​
}

局部变量表

存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。

这个区域一共会产生以下两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。
  2. 虚拟机在动态扩展时无法申请到足够的内存,会抛OutOfMemoryError异常。

本地方法栈(线程私有)

当java需要与一些底层系统或硬件交互时,这个时候需要通过调用native本地方法实现,本地方法栈和虚拟机栈的作用差不多,区别无非是本地方法栈为虚拟机使用的native方法服务,而虚拟机栈为jvm执行的java方法服务。

方法区(线程共享)

方法区用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据

方法区、永久代、元空间的关系

方法区是jvm定义的一种规范,是所有虚拟机都要遵守的约定,而永久代和元空间都是实际某个虚拟机针对方法区的一种实现。永久代是JDK8之前Hotspot虚拟机对方法去的实现,也就是说在JDK8以前的Hotspot虚拟机中,方法区也被称为永久代,而在JDK8之后被元空间取代。

永久代和元空间的区别

要说他们的区别先贴上一张以前博客里的图

先说一下不管是永久代还是元空间他们都是Hotspot针对方法区的一种实现,两者最大的区别在于永久代是在jvm虚拟机中分配内存,即上图的左半部分,元空间则分配在本地内存中。
为什么要做这样一种改变呢?
因为很多类是在运行期间加载的,这部分类加载的空间不可控,如果这部分内存是在jvm内存里分配的话,分配太大那么jvm其他区域可用内存就会变小,如果分配太小,就容易出现方法区内存溢出。所以JDK8中选择把方法区分配在本地内存,这样做的好处是元空间的大小不会受限于虚拟机分配的内存大小,就不会那么容易出现内存溢出。

JVM规范规定:当方法区无法满足内存分配需求时,将抛出OOM异常

运行时常量池(方法区的一部分,线程共享)

这一部分区域主要存放静态变量,字面量,符号引用

字面量:字符串(JDK7之后移动到堆)、final常量、基本数据类型的值
符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

JDK6中所有常量池数据是存放在永久代中,但到JDK7之后Hotspot把永久代中的字符串常量、静态变量迁移到了堆中,后面的jdk8并没有对这部分内容进行迁移,在jdk8中字符串,静态变量数据还是放在堆中,所以常量池只是在jvm规范定义上属于方法区,但Hotspot在实现的时候一部分实际上保存在堆中了。

堆区(线程共享)

堆是jvm所管理的最大内存区域,在jvm启动时创建。此内存区域存放的都是对象实例。jvm规范中提到:所有对象实例以及数组都要在堆上分配。

堆是垃圾回收器管理的主要区域,因此很多时候称之为“GC堆”。根据jvm规范规定的内容,堆可以处于物理上不连续额内存空间中。堆在主流的虚拟机中都是可扩展的(-Xmx设置最大值,-Xms设置最小值)。

如果在堆中没有足够的内存完成实例分配并且堆也无法再拓展时,将会抛出OOM。

JVM运行时内存分区相关推荐

  1. [转]JVM运行时内存结构

    [转]http://www.cnblogs.com/dolphin0520/p/3783345.html 目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的 ...

  2. JVM运行时内存概念-堆栈及新生代、老年代、持久代

    JVM内存有一些按不同标准划分的概念,这里来理清一下. 一.首先java虚拟机规范定义了java运行时数据区在概念上应该有的分区,这是抽象概念不对应也不限制物理上的具体实现,不同的虚拟机可以有不同的实 ...

  3. java runtime类 heap_Java 进阶(一) JVM运行时内存模型

    1.JVM运行时数据区域的划分 a.程序计数器(Program Counter Register) 一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.每个线程拥有独立的一个计数器,如果 ...

  4. 尝试用HSDB分析JVM运行时内存理解Java多态实现机制

    测试代码 // 接口 package ziya; public interface TestParent {void show(); }package ziya; public class Paren ...

  5. 在没有任何数据时进行无效的读取尝试。_技术转载——JVM运行时内存是怎么分布的?...

    写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下! GitHub地址:https://github.com/ ...

  6. 三年Java开发,你连基础的JVM运行时内存布局都忘了

    面:为什么要使用双亲委派机制去加载类? 答:避免多份同样字节码的加载,浪费内存. 类的加载方式 隐式加载:new 显示加载:loadClass.forName等 类的装载过程如下图: 面:loadCl ...

  7. JVM 运行时内存空间详解——元空间

    通过上一篇文章,我们大体了解了JVM的整体架构,其分为:元数据(JDK7是方法区).堆.虚拟机栈.本地方法栈.程序计数器几个部分. 本篇文章,咱们对元空间进行剖析,一探究竟. 1. 元空间介绍 在JD ...

  8. JVM运行时内存结构学习

    学习JVM运行模型比较重要,先看一幅图片: 运行时数据区(内存结构) :  1.方法区(Method Area) 类的所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在这里定义.简单来说, ...

  9. JVM运行时内存使用情况监控

    java 语言, 开发者不能直接控制程序运行内存, 对象的创建都是由类加载器一步步解析, 执行与生成与内存区域中的; 并且jvm有自己的垃圾回收器对内存区域管理, 回收; 但是我们已经可以通过一些工具 ...

最新文章

  1. 稀疏矩阵快速转置核心代码
  2. 137% YOLOv3加速、10倍搜索性能提升!百度飞桨推出模型压缩神器
  3. Post with HttpClient
  4. ES什么时候会平衡分片
  5. 【学习笔记】SAP Fiori相关概念介绍
  6. 为什么visual的联机浏览功能不能用_饥荒为什么不出联机手游?看到这3条缺陷,才明白原因...
  7. ElementUI中el-select下拉框选择不同的项控制其他控件(单选控件)的显示和隐藏
  8. 无关标签的一般长文本网页正文内容抽取
  9. 0003-Longest Substring Without Repeating Characters(无重复字符的最长子串)
  10. python if main_Python:if __name__ == '__main__'
  11. 【转】事务和锁机制是什么关系? 开启事务就自动加锁了吗?
  12. Git Bash推送GitHub不成功---密钥设置
  13. 如何使用HTML5嵌入视频
  14. Opencv--图像颠倒的问题
  15. 拖延心理学读后感ppt
  16. 解决linux下sudo更改文件权限报错xxxis not in the sudoers file. This incident will be reported.
  17. python爬虫--爬取小猪网的租房信息
  18. java 爬虫抢票_抢票爬虫 - nkandkn - 博客园
  19. 51nod 1629 B君的圆锥
  20. php js实现流程图,详解js中构造流程图的核心技术JsPlumb(2)_javascript技巧

热门文章

  1. [转载]监控 Linux 性能的 18 个命令行工具
  2. 求解组合问题的一个迭代算法
  3. 奋战杭电ACM(DAY10)1015
  4. 常见的数据库连接字符串收集
  5. opengl 关于glewGetContext没有定义
  6. Xcode 4 with External Static Library for iPhone Development
  7. 前端都应懂的入门基础-github基础
  8. VS2013 int main(int argc, char** argv)参数传递
  9. edit with idle 没反应_搬个家,猫咪不吃不喝甚至猝死?可能是你没做好“前戏”...
  10. R7-3 出租 (20 分)