JVM内存结构---《深入理解Java虚拟机》学习总结
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域的用途各不相同,同时也依据着各自的执行规则,独立的创建和销毁数据。
虚拟机内存的划分,如图所示:
线程之间互相独立的区域有:
虚拟机栈 、本地方法栈、程序计数器
线程可以共享数据的区域:
方法区 、堆
每个区域的作用分别如下:
程序计数器 Program Counter Register:
众所周知,虚拟机处理多线程时,是通过轮流的切换线程,来获取cpu的执行机会的。在虚拟机执行程序的过程中,当线程执行到某一位置时,虚拟机将cpu的执行机会出让给了其他线程,此时原有线程的执行(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )位置需要被记录下来,而新得到执行机会的线程,又需要提供上次执行的位置,以此来保证程序中的多个线程可以持续的并行的执行下去。
程序计数器的作用就是将各个线程下次所执行的(字节码)行号(准确来说是指令的地址)记录下来,以保证其下次执行时可以正确的执行。
根据程序计数器的作用,我们可以知道:
1、每个线程都在这个区域中都应该拥有一个只为自己提供服务的程序计数器,它们之间是独立存储,互不影响的存在。
2、我们还可以知道,程序计数器只记录字节码的行号,因此当线程执行本地方法(Native method)时,计数器的值是空。
3、程序计数器所耗费的内存空间非常小,因此这个区域是不会抛出OutOfMemoryError错误的。
虚拟机栈 VM Stack:
线程想要正常的运行下去,单靠程序计数器来记录行号是远远不止的。线程还需要拥有自己的运行空间,在这个空间中,虚拟机可以保存方法的执行顺序、方法的内部局部变量,方法在运算时,所需要的内存空间等。
在数据结构中,栈的特性最满足方法的进入返回的结构的。而这块区域的主(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )要作用就是线程在执行java方法时所需要记录的数据。因此我们将这块区域称之为虚拟机栈。但是要记住这里与我们在工作中通常指的栈并不等同,这个我会在后边介绍。
虚拟机栈的结构如下:
而对于每一个栈帧内部的划分又是这样的:
每一部分的作用如下:
(1)局部变量表:每一个方法都可以定义一个只属于自己的局部变量,当这个方法运行结束后,这个局部变量的生命周期也就宣告结束。所以每一个方法都应该拥有一个块属于自己的内存区域用来保存方法内部定义的局部变量。这块区域就是局部变量表,我们平常工作中所指的栈,实际上指的是虚拟机栈中的栈帧中的局部变量表。
(2)操作数栈:每个方法的内部都可以计算数据,而计算数据势必需要拥有一块内存区域,为虚拟机用来进行数值计算。因此在栈帧中,就需要有一块区域专门为当前方法计算数据使用,它就是操作数栈。
在每进行一次完整的计算之后,栈中的数据都已经出栈,所以操作数栈的空间在一个方法内部是可以反复使用的。所以虚拟机在分配内存大小时,只分配当前方法,单次完整计算所需要的最大内存空间给当前栈帧,以减少内存的消耗。
同时为了增加运行效率,减少数据的不断复制,在大部分虚拟机的实现中,将当前方法的局部变量表和上层方法的操作数栈的内存形成部分重叠,从而减少参数的不断复制而引起的性能消费。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
(3)动态连接:
虚拟机在执行方法时有两种形式被用来确定执行指令所对应的方法,
第一种是类加载时,可以直接确定要执行的方法,譬如静态方法,私有方法,final方法等。这种形式叫做静态解析。
第二种是在真正运行时,根据对象的真实引用来判断当前真正要执行的方法。这种形式称之为动态连接。
在字节码文件中,都存在一个常量池,在这个常量池中保存有大量的符号引用,这个符号引用是每一个方法的间接引用。在字节码指令的中,使用的是这个符号引用。但是在运行时阶段,肯定需要调用到要执行方法在内存中真实的地址。这就需要将间接引用转化成直接引用。而这里的“动态连接”就是为了保证在运行时阶段,方法可以正确的找到要调用的方法,每个栈帧将自己在运行时常量池中所对应的真实地址记录的位置。
这里需要注意的是,在栈帧中的动态连接和查找符号引用为真实引用中的动态连接,是两个概念。前者表示的是一个区域,后者表示的是一种查找方式。
(4)返回地址:
退出当前方法的方式有两种,第一种是遇到返回指令时,正常的退出当前方法。另一种形式是遇到没有捕获而被抛出的异常。无论何种返回形式,在方法退出后,栈帧的顶端都应是当前退出方法的上层方法。同时上层方法的执行状态也需要根据当前的返回结果重新调整。所以每个栈帧可以利用“返回地址”这块区域帮助上层方法恢复状态。
(5)附加信息:对于虚拟机规范中没有申明的,拥有指定存放位置的信息可以由各个虚拟机自己决定,放置到这个区域中。
本地方法栈 Native Stack
在虚拟机中,不但运行java方法,还会运行本地方法,也就是常见的Native 关键字修饰的方法。在虚拟机栈中,会为每个线程独立的开辟一个专门运行java语言(更准确的说应该是字节码)的方法(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )栈,但是对于本地方法,则是使用另外的一块内存区域来保存线程的调用状态,这块区域就是本地方法栈。他的作用跟虚拟机栈基本相似,其区别就是一个为java方法服务,一个为Native发光法服务。在虚拟机规范中,对于本地方法栈中的结构、方法的语言、方式,都没有强制规定,各个虚拟机可以自由的实现它。
Java堆 Java Heap
我们平常所说的,在堆中创建一个实例,指的就是这个堆。这是虚拟机所管理的内存中最大的一块。在虚拟机中,几乎所有的实例以及数组所分配的内存空间都会被放置在这个堆中。
由于java堆是对象实例的的主要存放位置,因此虚拟机的垃圾回收机制的主要工作区域。
根据Java的内存回收机制,我们可以将堆的大小和内容划分成如下的形式:
根据java堆的特性,我们也可以知道,这块区域是一块线程共享的区域。同时我们也可以看出来,这块区域,所可以使用在物理上非连续的内存,只要在逻辑上保持连续即可。
方法区 Method Area
方法区的主要作用是保存类信息、常量、静态变量以及即时编译后的代码等数据。这个区域中的数据仍然会被GC的代回收所涉及到。我们平常所说的永久代,指的就是这个区域。
尽管这个区域也被称之为永久代,但是当数据进入这个区域中,仍然可能会被回收。这个区域的回收目标主要是常量池的回收,以及类型的卸载。
运行时常量池 Runtime Constant Pool
这块区域属于方法区的中的一块子区域。
在Class文件中,除了有类版本、字段、方法、接口等,还有一个信息区(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )域是常量池。常量池中的数据将会在类被加载后,存在到运行时常量池中。
而类文件中的常量池主要包括各种字面量和符号引用。符号引用在讲解栈帧时,有所涉及。
字面量可以理解为java语言中的常量,如字符串、final修饰的变量等。
符号引用则是指以下三种固定信息:
(1)类和接口的全限定名称
(2)字段的名称和描述符
(3)方法的名称和描述符
java语言在编译成Class文件后,并没有关于方法和字段在内存中最终布局的信息。所以当虚拟机使用这些变量或方法时,需要先从常量池中,找到这些数据对应的符号引用,然后在方法的栈帧中的动态连接区域中找到其对应的内存真实位置。
在日常工作中,我们经常会遇到两种内存溢出的错误:
1、OutOfMemoryError
2、StackOverflowError
OutOfMemoryError指的是一个区域中,由于数据的不断增加,导致区域无法再从物理内存总申请到更大的空间,或者是区域所申请的空间已经到达虚拟机运行参数所给该区域设定的最大值,那么就会抛出这个错误。
StackOverflowError则指的是内存中的栈结构在不断的入栈,最终导致栈的深度超过了虚拟机所允许的栈深度时,所抛出的错误。
JVM内存结构---《深入理解Java虚拟机》学习总结的更多相关文章
- 深入理解java虚拟机学习笔记(一)JVM内存模型
上周末搬家后,家里的宽带一直没弄好,跟电信客服反映了N遍了终于约了个师傅明天早上来迁移宽带,可以结束一个多星期没网的痛苦日子了.这段时间也是各种忙,都一个星期没更新博客了,再不写之前那种状态和激情都要 ...
- 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略
写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...
- 深入理解Java虚拟机学习笔记(一)-----Java内存区域
一 概述 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题 ...
- 深入理解Java虚拟机---学习感悟以及笔记
一.为什么要学习Java虚拟机? 这里我们使用举例来说明为什么要学习Java虚拟机,其实这个问题就和为什么要学习数据结构和算法是一个道理,工欲善其事,必先利其器.曾经的我经常害怕处理内存溢 ...
- 深入理解java虚拟机学习笔记(二)垃圾回收策略
上篇文章介绍了JVM内存模型的相关知识,其实还有些内容可以更深入的介绍下,比如运行时常量池的动态插入,直接内存等,后期抽空再完善下上篇博客,今天来介绍下JVM中的一些垃圾回收策略. 一. ...
- 深入理解Java虚拟机 学习总结
一.运行时数据区域 Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区 1.1 程序计数器 程 ...
- 浅谈JVM - 内存结构(二)- 虚拟机栈|凡酷
2.1 定义 Java Virtual Machine Stacks(Java虚拟机栈) Java 虚拟机栈描述的是 Java 方法执行的内存模型,用于存储栈帧,是线程私有的,生命周期随着线程启动而产 ...
- 深入理解Java虚拟机学习笔记(三)-----类文件结构/虚拟机类加载机制
第6章 类文件结构 1. 无关性 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(即扩展名为 .class 的文件) 是构成平台无关性的基石. 字节码(即扩展名为 .class 的文 ...
- 深入理解Java虚拟机 - 学习笔记 1
Java内存区域 程序计数器 (Program Counter Register) 是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过 ...
- 深入理解java虚拟机学习笔记(二)
第三章 垃圾收集器与内存分配策略 概述 程序计数器.虚拟机栈.本地方法栈3个区随线程而生,随线程而灭.因此大体上可认为这几个区域的内存分配和回收都具备确定性.在方法/线程结束时,内存自然就跟着回收 ...
随机推荐
- C# DataTable 行转列
#region 根据datatable获得列名 /// <summary> /// 根据datatable获得列名 /// </summary> /// <param n ...
- About_PHP_验证码的生成
验证码就是一张图片,用到几个关键字: <?php session_start(); $arr = array( 'a','b','c','d','e','f','g','h','i','j',' ...
- Bigtable 论文 阅读笔记 - 原理部分
不支持markdown,桑心.更好的阅读体验请看:Github/Bigtable.md Paper: Google Bigtable paper Notes author: Lhfcws Wu Tim ...
- int(*f)(int)
int(*f)(int): 为指向函数的指针变量的定义方法,其中f为指向函数的指针变量,第一个int为函数返回值类型,第二个int为函数的形参类型.
- CSS3过渡、变形和动画
1.CSS3过渡 所谓CSS3过渡,就是使用CSS3让元素从一种状态慢慢转换到另一种状态.如鼠标的悬停状态就是一种过渡.如下例子: #content a{ text-decoration: n ...
- JQuery中on()函数详解
JQuery API中定义的on方法,专业名词很多,读起来并不是那么容易,而对于开发人员知道函数怎么使用就可以了.本文将JQuery的说明翻译如下: on(events,[selector],[dat ...
- 掌握Thinkphp3.2.0----连贯操作
其实在TP中,说起来语句中的各个关键词都被封装成了函数,将各个由关键词演变来的函数连起来就是所谓的连贯操作.只要注意各个函数直接参数传递的区别就可以了. 再者,不是所有的函数都可以进行连贯操作!!!比 ...
- js 表单验证控制代码大全
js表单验证控制代码大全 关键字:js验证表单大全,用JS控制表单提交 ,javascript提交表单:目录:1:js 字符串长度限制.判断字符长度 .js限制输入.限制不能输入.textarea 长 ...
- 【Git学习笔记】初始化Git仓库和版本回退
学习地址 http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 什么是版本库呢?版本库又 ...
- Log4J的入门简介学习【转】
原文:http://blog.csdn.net/lengyuhong/article/details/5832799 简介: Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以 ...