深入理解java虚拟机(一)虚拟机内存划分
Java虚拟机在执行Java程序时,会把它管理的内存划分为若干个不同的数据区。这些区域有不同的特性,起不同的作用。它们有各自的创建时间,销毁时间。有的区域随着进程的启动而创建,随着进程结束而销毁,有的则始终贯穿虚拟机整个生命周期。
Java虚拟机运行时内存区域主要分为七部分,分别是:程序计数器,Java虚拟机栈,本地方法栈,方法区,Java堆,运行时常量池,直接内存。
如上图所示(图片来源于网络):
蓝色区域包裹的部分为运行时几个数据区域:
白色的部分为线程私有的,既随着线程的启动而创建。每个线程都拥有各自的一份内存区域。它们是: JAVA栈(JAVA STACK),本地方法栈(NATIVE METHOD STACK),和程序计数器(PROGRAM COUNTER REGISTER)。
黄色部分是线程共享的,所有的线程共享该区域的内容。他们是:方法区(METHOD AREA),堆(HEAP)。
我们分别来介绍这些区域。
(1)程序计数器
程序计数器(program counter register)
学过计算机组成原理的都知道计算机处理器中的程序计数器。当处理器执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。
处理器的程序计数器是指寄存器,而java程序计数器是指一小块内存空间。java代码编译字节码之后,虚拟机会一行一行的解释字节码,并翻印成本地代码。这个程序计数器盛放的就是当前线程所执行字节码的行号的指示器。在虚拟机概念模型中,字节码解释器工作室就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理等都依赖于它。
Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,因此为了线程切换后还能恢复执行位置,每条线程都需要一个独立的程序计数器。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Java Native方法,这个计数器值为空。
而且程序计数器是Java虚拟机中没有规定任何OutOfMemoryError的区域。
(2)虚拟机栈
Java虚拟机栈(VM Stack)也是线程私有的,因此它的生命周期也和线程相同。它存放的是Java方法执行时的数据,既描述的是Java方法执行的内存模型:每个方法开始执行的时候,都会创建一个栈帧(Stack Frame)用于储存局部变量表、栈操作数、动态链接、方法出口等信息。每个方法从调用到执行完成就对应一个栈帧在虚拟机栈中入栈到出栈的过程。经常有人把Java内存分为堆内存和栈内存,这种是比较粗糙的分法,很大原因是大多数程序‘猿’最关注的,与对象内存分配最密切的区域就是堆和栈。局部变量表存放的是编译器可知的各种基本数据类型(boolean 、byte、int、long、char、short、float、double)、对象引用(reference类型)和returnAddress类型(它指向了一条字节码指令的地址)。其中64bit长度的long和double会占用两个局部变量空间(Slot),其余的数据类型只占用一个。局部变量表所需的内存空间是在编译时期确定的,在方法运行期间不会改变局部变量表的大小。在Java虚拟机规范中,对这部分区域规定了两种异常: 1、当一个线程的栈深度大于虚拟机所允许的深度的时候,将会抛出StackOverflowError异常; 2、如果当创建一个新的线程时无法申请到足够的内存,则会抛出OutOfMemeryError异常。
(3)本地方法栈
本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是十分相似的,他们之间的区别不过是虚拟机栈为Java方法字节码服务,而本地方法栈则为Native方法服务。在虚拟机规范中对本地方法使用的语言和使用方法与数据结构没有强制规定,因此具体的虚拟机可以自由实现它。Sun HotSpot虚拟机把本地方法栈和虚拟机栈合二为一。和虚拟机栈一样,本地方法栈也会抛出OutOfMemoryError 和 StackOverflowError异常。
接下来我们介绍的都是所有线程共享的区域了。
(4)堆
堆(heap)是虚拟机中最大的一块内存区域了,被所有线程共享,在虚拟机启动时创建。它的目的便是存放对象实例。
堆是垃圾收集器管理的主要区域,因此 很多时候也被成为‘GC’堆(Garbage Collected Heap)。
从垃圾回收的角度来讲,现在的收集器包括HotSpot都采用分代收集算法,所以堆又可以分为:新生代(Young)和老年代(Tenured),再细致一点,新生代又可分为Eden、From Survivor空间和To Survivor空间。
从内存分配的角度来讲,又可以分为若干个线程私有的分配缓冲区(Thread Local Allocation Buffer ,TLAB)。
当堆空间不足切无法扩展,会抛出OutOfMemoryError异常。
(5)方法区
方法去(Method Area)与Java堆一样,是各个线程共享的内存区域,用于存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
它有个别名叫做非堆Non-Heap。对于HotSpot开发者来说,很多人称它为“永久代”(Permanent Generation),但是两者并不等价,仅仅是因为HotSpot虚拟机设计团队把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已,这样HotSpot的垃圾收集器可以向管理堆一样管理这部分内存。但是因为永久代有“-XX:MaxPermSize的上限,使其更容易内存溢出。因此在JDK1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出去了。
当方法区无法满足内存分配需求的时候,会抛出OutOfMemoryError异常。
(6)常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中出了类的版本、字段、方法、接口等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后进入方法区存放。
运行时常量池相对于Class文件常量池的另外一个重要特征是具有动态性,运行期间也可能有新的常量池放入持重,比如String.intern()方法。
运行时常量池属于方法区一部分,自然会抛出OutOfMemoryError异常。
(7)直接内存
直接内存(Direct Memory)不属于虚拟机中定义的内存区域,而是堆外内存。
JDK1.4 中新加入了NIO(new Input/Output)类,引入了一种基于通道(Channel)和缓冲区(Buffer)的I/O方式,它可以使用Native函数直接分配堆外内存,然后通过Java堆中的DirectByteBuffer对象作为这快内存的引用进行操作。这样能在一些场景中显著提高新能性能。如果直接内存不足时,会抛出OutOfMemoryError异常。
深入理解java虚拟机(一)虚拟机内存划分的更多相关文章
- JAVA虚拟机运行时内存划分--运行时数据区域
Java虚拟机在执行java程序时会把内存划分为以下几个不同的数据区域: java虚拟机内存划分(运行时)1.线程私有的: 程序计数器(Program Counter Register):可以看作当前 ...
- Java运行时环境---内存划分
背景:听说Java运行时环境的内存划分是挺进BAT的必经之路. 内存划分: Java程序内存的划分是交由JVM执行的,而不像C语言那样需要程序员自己买单(C语言需要程序员为每一个new操作去配对del ...
- Java程序运行时内存划分
1.Java程序跨平台运行的原因 主要原因是:各种平台的JVM和字节码文件 Java源程序--具体平台的机器代码文件---被编译器翻译成平台无关的Class文件,又用特定JVM运行字节码文件,JVM在 ...
- java——变量、jvm内存划分
基本数据变量类型:byte.short.int.long.float.double.boolean.char eg : int i = 1; 引用数据变量类型:数组.类.接口.枚举.注解 eg : S ...
- Java虚拟机:JVM内存分代策略
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代.老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存 ...
- JVM-4-堆内存划分
什么是堆内存划分 Java虚拟机根据对象存活的周期不同,把堆内存划分为几块, 一般分为新生代.老年代和永久代,这就是JVM的内存分代策略.(JDK 1.8之后将最初的永久代取消了,由元空间 ...
- 【深入理解Java虚拟机】自动内存管理机制——内存区域划分
Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...
- 深入理解Java虚拟机 - 虚拟机内存划分
在内存管理方面,Java相对于C和C++的区别在于Java具有内存动态分配以及垃圾收集技术,但平时我们很少去关注JVM的内存结构以及GC,在出现内存泄露或溢出方面的问题,排查工作将变得异常艰难. ...
- 重读《深入理解Java虚拟机》一、Java虚拟机内存区域的划分
一.Java虚拟机内存区域如何划分 1.Java虚拟机内存区域的划分 区域名称 作用(用途) 类型 特点 虚拟机规定异常情况 内存分配与回收 其他说明 1 程序计数器 指示当前正在执行的字节码指令地址 ...
随机推荐
- Linux HDD information (SATA/SCSI/SAS/SSD)
举例一: [reistlin@reistlin.com ~]$ cat /proc/scsi/scsi | grep Model Vendor: ATA Model: OCZ-VERTEX2 3.5 ...
- Flask - 第一篇
首先,要看你学没学过Django 如果学过Django 的同学,请从头看到尾,如果没有学过Django的同学,并且不想学习Django的同学,轻饶过第一部分 一. Python 现阶段三大主流Web框 ...
- C# 判断字体是否存在以及安装
1. 字体安装 在实际开发项目中,需要在客户端安装字体,一种是通过代码将字体文件复制到系统FONT目录即可,另一种通过安装文件实现,至于其他方式还未知晓. 1.1 软安装 public cla ...
- vs2010下设置release版本调试设置
设置在Release模式下调试的方法: 1.工程项目上右键 -> 属性 2.c++ -> 常规 -〉调试信息格式 选 程序数据库(/Zi)或(/ZI), 注意:如果是库的话,只能( ...
- 前端开发之HTML篇一
主要内容: 一.HTML简介 二.HTML标签 三.HTML文档结构和注释 四.head标签及相关内容 五.body标签及相关内容 1️⃣ HTM ...
- VS2015 create a C++ console application based on WinRT
1. Enable /ZW 2. Disable /Gm 3. #using C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcpack ...
- Linux实战教学笔记14:用户管理初级(上)
第十四节 用户管理初级(上) 标签(空格分隔): Linux实战教学笔记-陈思齐 ---更多资料点我查看 1,账号管理 1.1 管理用户命令汇总 命令 注释说明(特殊颜色的必须掌握) useradd增 ...
- linux开机自检配置文件fstab变只读无法修改问题
控制linux开机自检的配置文件是/etc/fstab,在最近用的服务器中,发现fstab变成了只读权限,无法修改. 解决方法:RH5下,因磁盘改变,而导致系统停在Ctrl+d,此时需输入密码进入修改 ...
- 【LA3523 训练指南】圆桌骑士 【双连通分量】
题意 有n个骑士经常举行圆桌会议,商讨大事.每次圆桌会议至少应有3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置.如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防赞同和反 ...
- 高性能Web服务器Nginx的配置与部署研究(7)核心模块之主模块的非测试常用指令
1. error_log 含义:指定存储错误日志的文件 语法:error_log <file> [debug|info|notice|warn|error|crit] 缺省:${prefi ...