二、运行时JVM结构组成及作用

程序计数器

是否共享:否,线程私有,每个线程有1个独立的程序计数器!

所处位置:线程私有的内部区域

生命周期:与线程绑定

主要作用:

当前线程执行字节码的行号指示器!                           指哪打哪!

虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

存储内容:

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

为什么设计每个线程一个计数器?

JVM多线程之间切换时,如果只有1个计数器,也会产生并发问题;所以,为了让线程切换后也能执行正确的程序,每个线程设计1个程序计数器!

异常:此区域不抛出异常

虚拟机栈

是否共享:否,线程私有,每个线程1个栈区间

生命周期:与线程生命周期绑定

主要作用:

1)线程中java方法执行的逻辑模型;

每个java方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

执行该方法,就创建一个栈帧压栈;执行完栈帧出栈;

2)存放java方法的基本数据类型,引用数据类型

局部变量表存放基本数据类型,局部变量

如(boolean,byte,char,short,int,float,long,double)、对象引用(reference)和returnAddress类型。对象引用可能是指向对象堆内存的指针;

异常:

1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;

2)如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

本地方法栈

主要作用:

为JVM执行native方法!除了这个,其他都和虚拟机栈相同!

是否共享:否,线程私有,每个线程1个栈区间

生命周期:与线程生命周期绑定

异常:

同虚拟机栈

Java堆

是否共享:是,所有线程共享的内存。

主要作用:分配/存放对象实例,数组实例;

堆内存结构:堆内存=年轻代+老年代

年轻代Eden:含有Thread Local Allocation Buffer

没有直接设置老年代的参数,但是可以设置堆空间大小和新生代空间大小两个参数来间接控制。

老年代空间大小=堆空间大小-年轻代大空间大小

具体参考jvm参数设置

是否有垃圾回收:是,垃圾回收的主要场所

回收目标:没有引用的对象

要求:

1)java堆可扩展,扩展存放增加的对象实例!

2)不需要连续内存空间

异常:

堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

年轻代

1)年轻代作用:存放所有new新创建的对象

2)年轻代结构

年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配

Eden:8

From Survivor:1

To Survivor:1

部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

年老代

在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

方法区

是否共享:是,所有线程共享

主要作用:存储类元信息(类的数据结构),常量,静态变量,即时编译器编译后的代码数据。又叫类信息常量池

是否有垃圾回收:可选,一般在不在方法区执行垃圾回收,没啥效果!

回收目标:针对常量池的回收和对类类型的卸载

要求:

1) 可扩展

2) 不需要连续内存空间

异常:

当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常

永久代Permanent Generation

用于存放静态文件,类常量信息池,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。

JDK8移动永久代到Java堆

http://www.sczyh30.com/posts/Java/jvm-metaspace/

永久代是类的元数据,从JDK 8 开始把类的元数据放到本地java堆内存(native heap)中,这一块区域就叫 Metaspace,中文名叫元空间。

运行时常量池

方法区的一部分,

主要作用:用于存放编译期类生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。当java代码被编译成字节码(class)文件时,会将字面量(文本字符串,声明为final的常量值)、符号引用存放在class文件的常量池中。这部分内容将在类加载后进入方法区的运行时常量池中存放。

Class文件中除了有类的版本、 字段、 方法、 接口等描述信息外,还有一项信息就是常量池(Constant Pool Table),

堆外内存-硬件内存

NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。 这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆(堆外内存)中来回复制数据。

jvm内存归类

执行逻辑:

Java执行逻辑:栈区,程序计数器

Native执行逻辑:local栈,

数据存储:堆区

类元数据:方法区(类常量池)

JVM内存结构主要有三大块:堆内存、方法区和栈。

1)堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配;

2)方法区存储类的元信息(类的数据结构)、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);

3)栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。

二、运行时JVM结构组成及作用的更多相关文章

  1. Linux下tomcat运行时jvm内存分配

    tomcat运行时jvm内存分配 ⑴开发环境下在myeclipse中配置-Xms256m -Xmx512m -XX:NewSize=64m -XX:MaxNewSize=128m -XX:PermSi ...

  2. tomcat运行时JVM参数调整

    进入tomcat/bin目录 catalina.bat 中加入set JAVA_OPTS=-Xms210m -Xmx256m -Xmn70m -XX:PermSize=150m -XX:MaxPerm ...

  3. 使用Visual VM 查看linux中tomcat运行时JVM内存

    前言:在生产环境中经常发生服务器内存溢出,假死或者线程死锁等异常,导致服务不可用.我们经常使用的解决方法是通过分析错误日记,然后去寻找代码到底哪里出现了问题,这样的方式也许会奏效,但是排查起来耗费时间 ...

  4. 如何修改Tomcat运行时jvm编码

    问题: 最近在部署项目的时候出现数据乱码的情况,经过一番查看项目都是用的UTF-8编码格式,数据也是,但是经过调用接口传给对方就乱码了. 由于是部署在Windows环境下,Windows默认编码GBK ...

  5. 【Tomcat】tomcat启动后查看运行时JVM参数

    Tomcat优化配置参考http://www.cnblogs.com/qlqwjy/p/8007490.html 1.启动服务后访问localhost,点击Server Status

  6. JVM内核-原理、诊断与优化学习笔记(二):JVM运行机制

    文章目录 JVM启动流程 PC寄存器 方法区 保存装载的类信息 通常和永久区(Perm)关联在一起 Java堆 Java栈 Java栈 – 局部变量表 ** 包含参数和局部变量 ** Java栈 – ...

  7. IOS runtime动态运行时二

    在C#.Java中有编译时多态和运行时多态,在OC中,只有运行时的多态,这与它的运行机制有关.OC中,方法的调用是通过消息的传递来进行的.在IOS runtime动态运行时一http://www.cn ...

  8. 预编译加速编译(precompiled_header),指定临时文件生成目录,使项目文件夹更干净(MOC_DIR,RCC_DIR, UI_DIR, OBJECTS_DIR),#pragma execution_character_set("UTF-8")"这个命令是在编译时产生作用的,而不是运行时

    预编译加速编译 QT也可以像VS那样使用预编译头文件来加速编译器的编译速度.首先在.pro文件中加入: CONFIG += precompiled_header 然后定义需要预编译的头文件: PREC ...

  9. 浅谈java虚拟机|系列2|JVM运行时

    今天我们继续谈谈JVM架构. 今天主要讲讲JVM运行时, 先来一个图: 上篇文章,我们知道,JVM运行时,简单来说就是把class文件翻译成操作系统相关的机器码(或汇编语言),然后通过调用操作系统函数 ...

随机推荐

  1. VIM快速掌握

    vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的 ...

  2. PHP 根据 IP 获取定位数据

    使用的工具 GEOIP 配置 在PHP中使用 使用的工具 GEOIP: 什么是GepIP ? 所谓GeoIP,就是通过来访者的IP, 定位他的经纬度,国家/地区,省市,甚至街道等位置信息.这里面的技术 ...

  3. 005-多线程-集合-Map-ConcurrentSkipListMap

    一.概述 ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景. ConcurrentSkipListMap和TreeMap,它们虽然都是有序的哈希表.但是,第一,它 ...

  4. bat命令编写大全

    bat命令编写大全 摘自:https://blog.csdn.net/haibo19981/article/details/52161653 2016年08月09日 12:26:31 爱睡觉的猫L 阅 ...

  5. QML发布程序

    如果是在windows系统下,则最终打包成exe windeployqt  xxx.exe  -qmldir  C:\Qt\Qt5.9.6\5.9.6\mingw53_32\qml 注意使用Qt自己的 ...

  6. PAT 甲级 1058 A+B in Hogwarts (20 分) (简单题)

    1058 A+B in Hogwarts (20 分)   If you are a fan of Harry Potter, you would know the world of magic ha ...

  7. sonarqube-jenkins-config

    Sonar Config .Jenkinsfile config stage('SonarQube analysis') { steps { script { scannerHome = tool ' ...

  8. nginx.conf文件配置明细详解

    #etnx运行的用户和用户组 user nginx nginx; #工作进程数,建议设置为CPU的总核数 worker_processes ; #全局错误日志定义类型,日志等级从低到高依次为: #de ...

  9. vba Excel连接数据库

    PostgreSql: 第一步 在网上下载postres的驱动程序,之后安装,下载地址:https://www.devart.com/odbc/postgresql/download.html 第二步 ...

  10. Asp.Net Core集成Swagger

    工作中一个公司会有很多个项目,项目之间的交互经常需要编写 API 来实现,但是编写文档是一件繁琐耗时的工作,并且随着 API 的迭代,每次都需要去更新维护接口文档,很多时候由于忘记或者人员交替的愿意造 ...