理解JVM之Java内存区域
Java虚拟机运行时数据区分为以下几个部分:
方法区、虚拟机栈、本地方法栈、堆、程序计数器。如下图所示:

一、程序计数器
程序计数器可看作当前线程所执行的字节码行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。Java虚拟机的多线程是通过线程轮流切换以分配处理执行时间的方式进行的,因而为了确保线程切换后能够恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程计数器独立存储,互不影响,这类内存区域称为“线程私有”内存。当线程执行Java方法时,计数器记录的时正在执行虚拟机字节码指令的地址;如果执行Native方法,则计数器值为空(Undefine)。
程序计数器时唯一一个在Java虚拟机规范中没有任何规定OutOfMemoryError情况的内存区域。
二、Java虚拟机栈
Java虚拟机栈也是线程私有的,生命周期与线程相同。Java虚拟机栈是描述Java方法执行的内存模型:每个方法执行时都会创建一个栈帧(方法运行期间的基础数据结构),方法的执行过程对应着相应的栈帧在虚拟机中从入栈到出栈的过程。我们平时提到的栈就是虚拟机栈,也称为局部变量表部分。
局部变量表存放了编译期间的各种基本数据类型、对象引用和returAdress类型。其中,double和long占两个局部变量空间(Slot),其余数据类型占据一个。局部变量表所需内存是在编译期间完成分配的,当进入一个方法时,方法在帧中分配的局部变量空间大小是完全确定的,在方法运行期间局部变量表的大小不变。
Java虚拟机栈规定了两种异常状况:
- 线程请求栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常。
- 虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时抛出OutOfMemoryError异常。
三、本地方法栈
本地方法栈为虚拟机使用的Native方法服务,本地方法栈可根据虚拟机的具体要求自由实现。由的虚拟机(如Sun HotSpot虚拟机)直接将本地方法栈和虚拟机栈赫尔为一。
本地方法栈出现的异常为StackOverflowError和OutOfMemoryError异常。
四、Java堆
Java堆(Java Heap)是Java虚拟机内存中最大的一块。堆被所有线程共享,在虚拟机启动时创建。堆的唯一目的就是存放对象实例。一般来说,几乎所有的对象实例都在堆上分配内存。
Java堆是垃圾收集器管理的主要区域,因此又称为“GC堆”。(为什么莫名想到垃圾堆?)从内存回收角度由于收集器采用分代收集算法,故将Java堆细分为新生代,老生代;从内存分配角度将线程共享的堆划分为多个线程私有分配缓冲区。
Java堆处于物理不连接的内存空间中,只要逻辑上连续即可。如果堆中没有内存完成实例分配,且堆无法再扩展时抛出OutOfMemoryError异常。
五、方法区
方法区也是线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时候编译器编译后的代码等数据。Java虚拟机规范将方法区描述为堆的一个逻辑部分,但为与java堆进行区分,称它为Non-Heap(非堆)。由于HotSpot虚拟机用永久代来实现方法区,因而部分人习惯将方法区称为“永久代”。垃圾回收在方法区是较少出现的,这个区域内存回收主要目标是对常量池的回收和对类型的卸载。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
六、运行时常量池
运行时常量池是方法区的一部分,常量池是包含在Class文件中的一项信息,用于存放编译期生成的各种自面量和符号引用,这部分信息将在类加载后存放到方法区的运行时常量池中。一般来说,除了保存Class文件中的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。
运行时常量池与Class文件常量池相比具有动态性,并非时只有预置在Class文件中的常量池内容才能进入运行时常量池,运行期间也可以将新的常量放入池中,如String的intern()方法。当常量池无法再申请到内存时抛出OutOfMemoryError异常。
七、直接内存
直接内存并不是虚拟机运行时数据区的一部分,但这部分内存被频繁的使用,也会OutOfMemoryError异常的出现。
JDK1.4加入Input/Output类,引入基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,再通过Java堆中的DirectByteBuffer对象引用这块内存,以提高性能。它一般受到本机总内存与处理器寻址空间的限制,从而导致OutOfMemoryError异常。
本文主要参考《深入理解Java虚拟机——JVM高级特性与最佳实践》一书
另参考文章:
https://blog.csdn.net/u011116672/article/details/50994109
理解JVM之Java内存区域的更多相关文章
- 深入理解JVM - 1 - Java内存区域划分
作者:梦工厂链接:https://www.jianshu.com/p/7ebbe102c1ae来源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. Java与C++之间有一堵 ...
- 深入理解JVM(一)--Java 内存区域
一. 运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. Java虚拟机所管理的内存将会包括以下几个运行时数据区域: ...
- 深入理解JVM(二)Java内存区域
2.1 C.C++内存管理是由开发人员管理,而Java则交给了JVM进行自动管理 2.2 JVM运行时数据区:方法区.堆(运行时线程共享),虚拟机栈.本地方法栈.程序计数器(运行时线程隔离,私有) 1 ...
- JVM之Java内存区域
JVM之Java内存区域 世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程. 一.JAVA内存区域 谈及JAVA虚拟机运行时数据区域就不得不祭出这张经典的图了: ...
- 学习jvm(一)--java内存区域
前言 通过学习深入理解java虚拟机的教程,以及自己在网上的查询的资料,做一个对jvm学习过程中的小总结. 本文章内容首先讲解java的内存分布区域,之后讲内存的分配原则以及内存的监控工具.再下来会着 ...
- 深入理解JVM(6)——Java内存模型和线程
Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM)用来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果(“即Ja ...
- 史上最详细JVM,Java内存区域讲解
本人免费整理了Java高级资料,一共30G,需要自己领取:传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q 运行时数据区域 JVM载执行Jav ...
- JVM:Java内存区域与内存溢出异常
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁时间,有些区域随着虚拟机进程的启动而存在,有些区域依赖用户线程的启动和 ...
- 深入理解虚拟机之Java内存区域
1 概述 对于Java程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个new 操作去写对应的delete/free操作,不容易出现内存泄漏和内存溢出问题.正是因为 ...
随机推荐
- python3.6使用f-string来格式化字符串
这里的f-string指的是以f或F修饰的字符串,在字符串中使用{}来替换变量,表达式和支持各种格式的输出.详细的格式化定义可以看官方文档 >>> a, b = 30, 20 > ...
- 10-05 Java 内部类概述和讲解
内部类的概述 /* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部类的成员,包括私有. B: ...
- [转]Use HandleBars in Express
http://fraserxu.me/posts/Using-Handlebarsjs-with-Expressjs/ 在Express项目中使用Handlebars模板引擎 31 Aug 2014 ...
- docker学习实践之路[第一站]环境安装
安装虚拟机(VMware Workstation) 这步就不多说了,下载完软件之后一路点击下一步,直至安装完成. 安装Ubuntu 16.4 server 下载ubuntu 16.4,并安装在虚拟机中 ...
- Spark实战1
1. RDD-(Resilient Distributed Dataset)弹性分布式数据集 Spark以RDD为核心概念开发的,它的运行也是以RDD为中心.有两种RDD:第一种是并行Col ...
- android初探
随着nodejs的不断发展,前端的范围越来越大,所以,适当的了解移动端是非常有必要的,比如使用RN开发app,前端必须要和安卓工程师沟通共同开发,那么学习android的基本知识就很重要了,因为目前安 ...
- QT开发环境搭建
一.Qt发展史 1991年,由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架: 2008年,Nokia从Trolltech公司收购Qt, 并增加LGPL的授权模式: 2011年,Digia从N ...
- Git for Windows之使用SSH协议开通公钥免密登陆功能
1.删除Https的通信方式,建立SSH的通信方式 (1).查看当前的通信方式 当前是使用Https的方式与远程仓库进行通信 (2).删除HTTPS的通信方式 ok,HTTPS通信方式已删除 (3). ...
- 全网最详细的Windows系统里Oracle 11g R2 Client客户端(64bit)安装后的初步使用(图文详解)
不多说,直接上干货! 前期博客 全网最详细的Windows系统里Oracle 11g R2 Client(64bit)的下载与安装(图文详解) 命令行方式测试安装是否成功 1) 打开服务(cmd— ...
- Double与BigDecimal 精度问题
转自:http://superivan.iteye.com/blog/963628 [1] 精确的浮点运算: 在Java里面,有时候为了保证数值的准确性需要精确的数据,先提供一个例子就可以发现问题了: ...