其实很多学习Java的人,或者工作有几年的人都不是很明白JAVA内存模型,也说不清内存模型,总体上感觉熟悉,但是说不上来。也有一些人分不清楚JVM内存分区和Java内存模型。
什么是JVM内存分区?
JVM内存分区具体指的是JVM中运行时数据区的分区
Java程序执行的流程
.java文件被Java Compiler编译为.class字节码文件,随后Class Louder加载各类的字节码文件,加载完后交由Execution Engine执行。执行引擎负责具体的代码调用及执行过程。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。
运行时数据区(Runtime Data Area)
名称 | 特征 | 作用 | 可配置参数 | Error |
---|---|---|---|---|
堆 | 线程共享,生命周期与虚拟机相同,可以不使用连续的内存地址。占用区域最大,可扩展 | 用于存放对象实例(包括数组) | -Xms -Xsx -Xmn | OutOfMemoryError |
方法区 | 线程共享,生命周期与虚拟机相同,可以不使用连续的内存地址。含有Runtime Constant Pool(运行时常量池)。 | 储存已被JVM加载的类信息、常量、静态变量、即时编译后的代码数据 | -XX:PermSize:16M -XX:MaxPermSize:64M | OutOfMemoryError |
虚拟机栈 | 线程私有,生命周期与线程相同,使用连续的内存空间。总数与线程数关联。 | Java方法执行的内存模型,每个方法执行时都会创建一个栈桢来存储方法的的变量表、操作数栈、动态链接方法、返回值、返回地址等信息 | -Xss | StackOverflowError OutOfMemoryError |
本地方法栈 | 线程私有,生命周期与线程相同,使用连续的内存空间。总数与线程数关联。 | 本地方法栈为虚拟机执行native方法而服务 | StackOverflowError OutOfMemoryError | |
程序计数器 | 线程私有,生命周期与线程相同,占用内存小 | 指示当前执行字节码的行号,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能 | 此内存区域是唯一 一个在Java 虚拟机规范中没有规定任何OutOfMemoryError情况的区域 |
什么是Java内存模型?
Java内存模型:Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在。目的是解决由于多线程并发编程通过内存共享进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题,即保证内存共享的正确性(可见性、有序性、原子性)。JVM运行程序的实体是线程,每个线程创建时JVM会为其创建相应的工作内存(空栈间),用于储存线程私有数据,JMM中规定所有变量都存储在主内存上,所有线程都可访问,线程对于变量的操作(赋值、读取等)必须在工作内存进行,操作完成首在写回主内存,这样个线程之间就无法相互访问,线程间的通信(传值)必须通过主内存来完成。
- 主内存:MM规定所有的变量都必须在主内存中产生
- 工作内存:JVM中每个线程都有自己的工作内存,是线程私有的,可以类比CPU的高速缓存。线程的工作内存保存了线程需要的变量在主内存中的副本。
并发编程的问题
多线程并发编程会涉及到以下的问题:
- 原子性:指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。
- 可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
- 有序性:程序执行的顺序按照代码的先后顺序执行,多线程中为了提高性能,编译器和处理器的常常会对指令做重排(编译器优化重排、指令并行重排、内存系统重排)