JVM探秘1--JVM内存运行时区域划分
Java程序员一般不需要太关注内存,因为操作内存的权力都交给了Java虚拟机,但是Java程序员必须需要了解JVM是如何使用内存的,否则一旦内存出现泄漏或事溢出的话,就会一筹莫展不知道从哪去入手排查问题。
一、JVM内存模型
JVM在运行时会把它管理的内存划分成若干个不同区域,每个区域有各自不同的用处,以及不同的创建和销毁的时间,有的随着JVM进程启动而存在,而有的需要随着用户线程的启动和结束而创建和销毁,主要内存区域划分如下图示:

主要分成两大类,线程共享的区域和线程独享的区域。
线程共享区域
1.堆
堆内存是JVM管理的最大的内存区域,堆内存被所有线程共享,随着虚拟机的启动而创建,存放的全部是对象实例,几乎所有的对象实例都是在堆内存中被分配内存。随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术会导致对象不一定会在堆中分配内存了。
堆内存是垃圾回收主要的区域,而主流的垃圾回收都是采用的分代收集算法,所以堆内存也常常会被分为新生代和老年代,新生代又可以被分成Eden区、From Survivor区和To Survivor区。堆内存虽然可以划分成很多区,但仅仅是逻辑上的区分,实际存储的都是对象实例。而且堆内存可以在物理内存空间上不连续,只需要逻辑上连续即可。一般JVM优化主要也是针对堆内存来进行优化。而堆内存的扩展主要是通过-Xms和-Xmx参赛来进行配置,当堆内存不足以再创建新对象时就会抛出OutOfMemoryError异常
2.方法区
方法区和堆内存一样也是所有线程共享的,主要存储已经被虚拟机加载的类信息、静态变量、常量、即时编译器编译后的代码等信息。由于方法区存储的一般都是不变的数据,所以垃圾回收很少会在这个区域进行。方法区的垃圾回收主要是针对常量池和对类型的卸载。这个区域如何内存不足也会抛出OutOfMemoryError异常。
线程独享区域
1.虚拟机栈
虚拟机栈属于线程私有,随着线程的创建而创建,随着线程的销毁而销毁。而每执行一个Java方法,都会在虚拟机栈中创建一个栈帧 (Stack Frame),栈帧中又包含局部变量表、操作栈、动态链接和方法出口等信息。每一个Java方法被调用直到方法执行完成的过程,对应着一个栈帧在虚拟机栈中的入栈到出栈道过程。一般有一种说法是Java内存分为堆内存和栈内存,这种是比较笼统的,这里的栈内存实际指的仅仅是虚拟机栈中的一个栈帧的局部变量表区域。局部变量表中存储八种基本数据类型、对象引用(不同的虚拟机可能是指向对象起始地址的引用指针,也可能是指向一个对象的句柄或与对象相关的位置)
虚拟机栈内存区域每执行一个方法,有创建一个栈帧压栈,执行完后出栈,栈的特点是先进后出,后进先出,如果线程请求的栈深度大于虚拟机允许的深度,会抛StackOverFlowError(栈溢出);而如果虚拟机栈内存不足且扩展时也无法申请到足够的内存的话,则会抛OutOfMemoryError(内存溢出)
1.1、局部变量表:存储方法局部变量
1.2、操作数栈:出入栈进行操作数的计算
1.3、动态连接:动态寻址的过程,比如方法定义UserService userService; 那么实际运行的时候需要找到UserService接口具体是由哪个对象实现的
1.4、顾名思义就是方法的出口
下面以简单例子查看虚拟机栈的工作方式:
public static Integer num = 10;
public int add(int i){
int j = 5;
int k = i+j;
j++;
k = num + j;
return k;
}
定义一个简单的add方法,定义一个静态变量,代码编译之后结果如下:
public int add(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=2
0: iconst_5
1: istore_2
2: iload_1
3: iload_2
4: iadd
5: istore_3
6: iinc 2, 1
9: getstatic #2 // Field num:Ljava/lang/Integer;
12: invokevirtual #3 // Method java/lang/Integer.intValue:()I
15: iload_2
16: iadd
17: istore_3
18: iload_3
19: ireturn
LineNumberTable:
line 7: 0
line 8: 2
line 9: 6
line 10: 9
line 11: 18
(具体每一步的含义及局部变量表和操作数栈的变化情况在《JVM探秘6--图解虚拟机栈的局部变量表和操作数栈工作流程》详细图解)
2.程序计数器
程序计数器占有的内存较小,主要存储当前线程执行的字节码的行号,字节码执行器工作时需要根据程序计数器来选取下一条需要执行的字节码指令,由于JVM的多线程数通过线程轮流切换被分配CPU执行的,一个CPU同一时间只能处理一个线程的一个指令,为了在线程切换后能够恢复到正确的指令位置,就需要每个线程都有一个独立的程序计数器,各个线程之间的程序计数器互不影响。如果线程正在执行JAVA方法,则计数器记录正在执行的字节码指令的地址,如果正在执行的事本地方法,计数器值则为空。程序计数器由于存储的值只有字节码地址,没有扩展的需要,所以这个区域是不会出现OutOfMemoryError情况的。
3.本地方法栈
本地方法栈和虚拟机栈类似,不同的是虚拟机栈是为Java方法服务,而本地方法栈是为本地方法服务,而本地方法使用的语言不同的虚拟机是不一样的,也有的虚拟机会将本地方法栈和虚拟机栈合二为一。本地方法栈和虚拟机栈一样也会抛StackOverFlowError和OutOfMemoryError。
除了上面的JVM运行时内存划分,还有一类内存叫做直接内存,这类内存是不受JVM管控的,但是也会出现OutOfMemoryError异常。JDK1.4加入了NIO,引入了通道和缓冲区的I/O方式,可以使用本地方法直接分配堆外内存,然后通过一个存储在Java堆里的DirectByteBuffer对象作为这块内存的引用进行操作,可以避免java堆和native堆中来回复制数据而提高性能。直接内存不受JVM控制,但是会受到机器总内存的影响,如果JVM内存分配过大加上其他的内存大于了服务器的总内存,就会导致直接内存无法分配,同样也会出现OutOfMemoryError异常。
JVM探秘1--JVM内存运行时区域划分的更多相关文章
- JVM知识总结-运行时区域划分
区域简介 JVM运行时区域有些随着虚拟机进程的启动而存在,有些依赖于用户线程的启动和结束而建立和销毁,大致分为以下几类:方法区,虚拟机栈,本地方法栈,堆,程序计数器,概念图如下(源于<深入理解J ...
- JVM学习笔记:Java运行时数据区域
JVM执行Java程序的过程中,会使用到各种数据区域,这些区域有各自的用途.创建和销毁时间.根据<Java虚拟机规范>,JVM包括下列几个运行时数据区域,如下图所示: 其中红色部分是线程私 ...
- JVM运行时区域详解。
我们知道的JVM内存区域有:堆和栈,这是一种泛的分法,也是按运行时区域的一种分法,堆是所有线程共享的一块区域,而栈是线程隔离的,每个线程互不共享. 线程不共享区域 每个线程的数据区域包括程序计数器.虚 ...
- JVM笔记【1】-- 运行时数据区
目录 (一)java内存区域管理 1.1 程序计数器 1.2 虚拟机栈 1.3 本地方法栈 1.4 java堆 1.5 方法区 1.5.1 运行时常量池 (二)直接内存 (一)java内存区域管理 C ...
- Java 内存管理、JVM 工作原理与 Java 运行时系统
Java 虚拟机规范中说明:所有的对象实例(all class instances)以及数组都要在堆上分配: the heap is the runtime data area from which ...
- JVM探秘:Java内存区域
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 概述 Java 虚拟机为程序员分担了很多内存管理的工作,不再像 C/C++ 那样容易出 ...
- JVM 专题十二:运行时数据区(七)对象的实例化内存布局与访问定位
1. 对象的实例化 1.1 创建对象的方式 new 最常见的方式 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 Class的newInstance() ...
- JVM之基础概念(运行时数据区域、TLAB、逃逸分析、分层编译)
运行时数据区域 JDK8 之前的内存布局 JDK8 之后的 JVM 内存布局 JDK8 之前,Hotspot 中方法区的实现是永久代(Perm),JDK8 开始使用元空间(Metaspace),以前永 ...
- 深入浅出JVM(一):运行时数据区域
程序计数器 线程私有 指向了正在执行的虚拟机字节码指令的地址:如果是本地方法,数值为空 没有 OutOfMemoryError 错误的区域 Java虚拟机栈 线程私有: 生命周期与线程相同: 代表着 ...
随机推荐
- js 暂时存储 sessionStorge
H5的storage有sessionstorage&localStorage,其中他们的共同特点是API相同 下面直接上代码,storage中的存储与删除: <!DOCTYPE html ...
- TCP连接的状态与关闭方式,及其对Server与Client的影响
1. TCP连接的状态 首先介绍一下TCP连接建立与关闭过程中的状态.TCP连接过程是状态的转换,促使状态发生转换的因素包括用户调用.特定数据包以及超时等,具体状态如下所示: CLOSED:初始状态, ...
- 最全36种python设计模式
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用.设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多软件开发人员经过 ...
- redis数据操作笔记
redis是key-value的数据结构,每条数据都是一个键值对键的类型是字符串 注意:键不能重复,值的类型分为五种:字符串string 哈希hash 列表list 集合set 有序集合zset 一. ...
- 115、如何构建Android MVVM 应用框架(转载)
转载:http://android.jobbole.com/85198/
- System.InvalidOperationException:“线程间操作无效: 从不是创建控件“txtPortName02”的线程访问它。”
“System.InvalidOperationException”类型的未经处理的异常在 System.Windows.Forms.dll 中发生 其他信息: 线程间操作无效: 从不是创建控件“tx ...
- mysql之表格的关联关系
1.’基本模式有多对一,多对多,一对一.关联的两个基本组建为外键列和参照列 典型的多对一模式,很普遍,如部门表和员工表,即一个部门可以有多个员工. 对于多对多的模式,就需要建立中间表,将其转换为多对一 ...
- hibernate07--关联映射
单向的一对多关联 创建对应的实体类以及映射文件 package cn.bdqn.bean; /** * * @author 小豆腐 *街道对应的实体类 * *单向的多对一关联 */ public cl ...
- plsql中文乱码
一.关于PLSQL无法正确显示中文 刚才下载安装了PLSQL Developer 9.0.0.1601 汉化绿色版,执行SQL查询语句,发现显示的数据中只要有中文都会以?表示. 原因:客户端跟服务器的 ...
- 15.vue动画& vuex
Vue.config.productionTip = false; ==是否显示提示信息== ==import/export== export xxx 必须跟跟对象或者和定义一起 对象: export ...