普通进程栈区,在JVM通常仅仅用作线程栈,以下图所示java
首先是永久代。永久代本质上是Java程序的代码区和数据区。Java程序中类(class),会被加载到整个区域的不一样数据结构中去,包括常量池、域、方法数据、方法体、构造函数、以及类中的专用方法、实例初始化、接口初始化等。这个区域对于操做系统来讲,是堆的一个部分;而对于Java程序来讲,这是容纳程序自己及静态资源的空间,使得JVM可以解释执行Java程序。算法
其次是新生代和老年代。新生代和老年代才是Java程序真正使用的堆空间,主要用于内存对象的存储;数组
那么这些区域如何对应JVM的内存模型呢,首先看一张经典的JVM内存模型图:服务器
线程栈:在JVM中用作线程栈,每一个线程都会在这个区域开辟私有栈数据结构
程序计数器是一块较小的内存空间,它能够看作是当前线程所执行的字节码的行号指示器,字节码解释器经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支循环,跳转,异常处理,线程恢复等基础功能,特别注意的是,若是线程正在执行的是一个java方法那这个计数器记录的是字节码指令的地址(位置),若是是执行的是Native方法,这个计数器为空jvm
程序计数器该部份内存是惟一不会发生OutOfMemoryError异常的区域函数
java虚拟机栈,也在这个线程栈中,线程私有,每一个方法执行的同时都会建立一个栈帧,用于存储局部变量表,操做数栈,动态连接,方法出口等信息.性能
局部变量表,存放了编译期可知的各类基本数据类型(boolean,byte,char short,int float,long,double),对象引用(reference,指向对象的指针,或者表明对象的句柄)和returnAddress类型操作系统
在jvm规范中,对这个区域规定了两种异常情况:1.若是线程请求的的栈深度大于虚拟机所容许的深度,将抛出StackOverFlowError异常,若是虚拟机栈能够动态扩展,扩展时没法申请到足够的内存将抛出OutOfMemoryError异常线程
本地方法栈,与虚拟机栈的做用很是类似,只不过是服务于Native方法,也会抛出两种异常
inux的普通进程所使用的堆区,在jvm(Hotspot)进程中分为永久新生老年代三块区域
永久代,对应于 jvm的方法区,
方法区:用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码,等数据.要特别注意的是.方法区和永久代并非等价的,这要取决于虚拟机的类型,牢牢是由于HotSpot使用永久代来实现方法区.对于其余虚拟机并不存在永久代的概念,
运行时常量池是方法区的一部分,所以它也在永久代,用于存储编译期间生成的各类字面量和符号引用,什么叫字面量呢,就是int i =1;这个1就是字面量,String str= "abc";这个abc是字面量,什么叫符号引用呢,就是在一个类中Student stu = new Student("张三",28) new出来的Student对象在编译后未加载前显然不知道其实际内存地址,所以在class文件中用一串无异议的符号来代替对象的内存首地址,等class文件通过一系列的加载检验以后分配完内存,会将符号引用替换成直接引用
新生代和老年代
Java堆:新生代和老年代才是对应于JVm内存模型中的java堆,它是被全部线程共享的一个内存区域,在虚拟机启动时建立.它的惟一目的就是存放对象实例,几乎全部的对象实例都在这里分配内存,包括数组
java堆是垃圾收集器管理的主要区域,所以,不少时候也被称为GC堆,因为如今收集器基本都采用分代收集算法,因此Java堆细分为新生代和老年代;再细致一点的有Eden空间,FROM Survivor空间,To Survivor空间等.
从内存分配的角度来看,线程共享的java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer TLAB),进一步划分是为了更好的回收内存,或者更快的分配内存.
根据JVM规范,java堆能够处于物理上不连续的内存空间中,只要逻辑上是连续的就能够,若是在堆中内有内存完成实例分配,而且对没法扩展出足够的内存,将会抛出OutOfMemoryError异常
JVM中的直接内存,并非虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,可是这部份内存也被频繁地使用,并且也可能致使OutOfMemoryError,
在jdk1.4中新加入了NIO类,引入了一种基于通道(Channel)与缓冲区(BUffer)的IO方式,它可使用Native函数库直接分配内存,而后经过一个存储在java堆中的DirectByteBuffer对象做为这块内存引用进行操做,这样能在一些场景中显著提升性能,由于避免了Java堆和Native堆中来回复制数据.以下图:NIO使用的堆外内存
显然,本机直接内存的分配不会受到Java堆大小的限制,可是,既然是内存,确定仍是会受到本机总存的(包括RAM以及swap区域或者分页文件),大小以及处理器寻址空间的限制.服务器管理员在配置虚拟机参数时,会根据实际内存设置-Xmx等参数信息.但常常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操做系统级的限制),从而致使动态扩展时出现OutOfMemoryError异常
https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554703&idx=1&sn=4b2ce0d3fa9017adb2dac9843f097882&chksm=f3f833d9c48fbacf242749ec8f40197d9ea5463dc46f47afc62fd93b3fe4f433a723ceddd515#rd