【番外篇】JVM 内存区域
2016-02-07 15:21
288 查看
今天不写关于Android的东西,来点其它的。
JVM在执行程序的过程中会把内存划分为几个不同的区域,每个区域都有自己的生命周期以及用途,有的区域会随着VM的启动而存在,而有的区域会随着用户线程的启动而存在以及结束而销毁。那么JVM到底会把内存分为哪几个区域呢?
根据JVM的规范,JVM会把内存分为以下几个区域:程序计数器(Program Counter Register),虚拟机栈(VM Stack),本地方法栈(NativeMethod Stack),方法区(Method Area),堆(Heap)
1. 程序计数器:它在内存中占据一块比较小的区域,是每个线程所执行的字节码的行号标识器,也就是说,java字节码的解释器的工作要依赖这个行号,因为只有知道了行号这个解释器才能去到指定的行号处读取所需要执行的字节码指令,注意,循环,跳转,以及异常处理,线程恢复等都要依赖这个程序计数器。
我们知道,在每一个时刻,一个CPU的核心只能执行一个线程中的一条指令,因此,为了实现所谓的多线程我们采取了时间片轮转的方式,既然要轮转,不同的线程之间就会切换,那为了在频繁的线程切换中能恢复到之前正确的执行位置,每个线程都有一个自己的程序计数器,每个线程间的计数器互不干涉相互独立,如果JVM执行的是一个java方法,这个程序计数器的值就是正在执行的虚拟机字节码的行号(或者说是地址),如果正在执行的是本地(Native)方法,这个计数器的值置为空。
2. 虚拟机栈:它和线程共存亡,也是线程私有的,每个方法在执行的时候会创建一个栈帧用来存储变量表,操作数栈,动态链接,方法出口等东西,每个方法从调用到完成返回的过程,也就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
3. 本地方法栈:它和虚拟机栈的功能大致类似,只不过是它们执行的方法不同而已,虚拟机栈执行java方法,而本地栈执行的是Native方法。
4. 堆:堆是JVM管理的最大的一块内存区域,也是所有线程都共享的一片区域,在JVM启动的时候创建,堆存在的最大价值就是用来存放对象实例,大多数对象实例都会在堆里分配内存,只有一小部分的对象实例会在其他的地方存储并分配内存。
堆也是执行GC操作的主要区域,从内存回收的角度来看,堆区可以细分为:新生代区和年老代区,再细一点的话,还可以分为:Eden空间,From Survivor空间以及To Survivor空间等等,不管它怎么细化,它里面也存储的都是对象实例,不同的分法也只是为了更好或更快的回收堆内存空间而已
根据规范,堆空间只要逻辑上是连续的就可以,物理上并不要求一定要连续,而且,空间的大小可以是固定的,也可以是动态拓展不固定的。
5. 方法区: 它和堆一样也是共享的区域,该区域一般用于存放JVM加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,它和堆一样可以不是连续的内存空间,可以不是固定的大小,甚至还可以不实现GC,当然,这不是说在方法区GC不重要,而是说这块区域GC很难达到预想中满意的效果,因为,方法区的GC操作涉及到类型的卸载和对常量池的回收,所以,条件比较苛刻难度较大。
6. 直接内存:它不属于JVM管理的内存部分,但是也被频繁的使用,直接内存不会受到堆大小的限制,但是,既然是内存就一定会受到物理总内存的限制以及CPU寻址空间大小的限制,所以,除了要注意虚拟机堆内存的大小限制以外,对于直接内存的大小限制也要时刻小心。
JVM在执行程序的过程中会把内存划分为几个不同的区域,每个区域都有自己的生命周期以及用途,有的区域会随着VM的启动而存在,而有的区域会随着用户线程的启动而存在以及结束而销毁。那么JVM到底会把内存分为哪几个区域呢?
根据JVM的规范,JVM会把内存分为以下几个区域:程序计数器(Program Counter Register),虚拟机栈(VM Stack),本地方法栈(NativeMethod Stack),方法区(Method Area),堆(Heap)
1. 程序计数器:它在内存中占据一块比较小的区域,是每个线程所执行的字节码的行号标识器,也就是说,java字节码的解释器的工作要依赖这个行号,因为只有知道了行号这个解释器才能去到指定的行号处读取所需要执行的字节码指令,注意,循环,跳转,以及异常处理,线程恢复等都要依赖这个程序计数器。
我们知道,在每一个时刻,一个CPU的核心只能执行一个线程中的一条指令,因此,为了实现所谓的多线程我们采取了时间片轮转的方式,既然要轮转,不同的线程之间就会切换,那为了在频繁的线程切换中能恢复到之前正确的执行位置,每个线程都有一个自己的程序计数器,每个线程间的计数器互不干涉相互独立,如果JVM执行的是一个java方法,这个程序计数器的值就是正在执行的虚拟机字节码的行号(或者说是地址),如果正在执行的是本地(Native)方法,这个计数器的值置为空。
2. 虚拟机栈:它和线程共存亡,也是线程私有的,每个方法在执行的时候会创建一个栈帧用来存储变量表,操作数栈,动态链接,方法出口等东西,每个方法从调用到完成返回的过程,也就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
3. 本地方法栈:它和虚拟机栈的功能大致类似,只不过是它们执行的方法不同而已,虚拟机栈执行java方法,而本地栈执行的是Native方法。
4. 堆:堆是JVM管理的最大的一块内存区域,也是所有线程都共享的一片区域,在JVM启动的时候创建,堆存在的最大价值就是用来存放对象实例,大多数对象实例都会在堆里分配内存,只有一小部分的对象实例会在其他的地方存储并分配内存。
堆也是执行GC操作的主要区域,从内存回收的角度来看,堆区可以细分为:新生代区和年老代区,再细一点的话,还可以分为:Eden空间,From Survivor空间以及To Survivor空间等等,不管它怎么细化,它里面也存储的都是对象实例,不同的分法也只是为了更好或更快的回收堆内存空间而已
根据规范,堆空间只要逻辑上是连续的就可以,物理上并不要求一定要连续,而且,空间的大小可以是固定的,也可以是动态拓展不固定的。
5. 方法区: 它和堆一样也是共享的区域,该区域一般用于存放JVM加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,它和堆一样可以不是连续的内存空间,可以不是固定的大小,甚至还可以不实现GC,当然,这不是说在方法区GC不重要,而是说这块区域GC很难达到预想中满意的效果,因为,方法区的GC操作涉及到类型的卸载和对常量池的回收,所以,条件比较苛刻难度较大。
6. 直接内存:它不属于JVM管理的内存部分,但是也被频繁的使用,直接内存不会受到堆大小的限制,但是,既然是内存就一定会受到物理总内存的限制以及CPU寻址空间大小的限制,所以,除了要注意虚拟机堆内存的大小限制以外,对于直接内存的大小限制也要时刻小心。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树