二、运行时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. Linux shell脚本 (十二)case语句

    case语句 case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构. case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令.case ...

  2. osg osgViewer::View::setUpViewInWindow()

    void ViewerBase::frame(double simulationTime) { if (_done) return; // OSG_NOTICE<<std::endl< ...

  3. Maven打包SpringBoot

    Pom文件提交plugin <build> <finalName>Site</finalName><!--文件名可自定义--> <plugins& ...

  4. react 点击事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. ELK之elasticsearch插件导致filebeat没有上传日志至elasticsearch解决办法

    使用filebeat收集nginx发现日志为上传,elasticsearch没有日志,kibana没有展示 查看filebeat日志 日志目录为/var/log/filebeat  下面有多个日志文件 ...

  6. 第二十四章 在线会话管理——《跟我学Shiro》

    目录贴:跟我学Shiro目录贴 有时候需要显示当前在线人数.当前在线用户,有时候可能需要强制某个用户下线等:此时就需要获取相应的在线用户并进行一些操作. 本章基于<第十六章 综合实例>代码 ...

  7. JsonSchema用法

    JsonSchema用法 简介 JSON Schema是基于JSON格式,用于定义JSON数据结构以及校验JSON数据内容.JSON Schema官网地址:http://json-schema.org ...

  8. 【c# 学习笔记】阻止派生类重写虚成员

    使用sealed 关键字可以防止一个类被其他类继承.同样,也可以使用sealed关键字来阻止派生类重写虚成员.如,我们希望Horse的继承类不再具有扩展Voice方法的行为.(上一章链接:https: ...

  9. .Net Core 请求上下文IHttpContextAccessor

    namespace Microsoft.AspNetCore.Http { public interface IHttpContextAccessor { HttpContext HttpContex ...

  10. Flutter TextField 文本输入框的基本属性及详解

    TextField 文本输入框 源码分析: const TextField({ Key key, this.controller, // 控制正在编辑文本 this.focusNode, // 获取键 ...