JVM内存结构

JVM内存结构主要由三大块:堆内存,方法区和栈。
堆内存:jvm管理的内存的最大的一块,在虚拟机启动的时候创建,该区域唯一的目的就是为了存放对象实例,几乎所有的对象实例都在这里分配(该内存区域存放了对象实例和数组(所有new的对象))。堆由年轻代和老年代组成,年轻代又分为三部分,eden空间,from survivor空间,to survivor空间,默认的年轻代按照8:1:1分配。
年轻代:程序新创建的对象都是在年轻代分配内存的。
老年代:用于存放多次新生代GC依然存在的对象,例如缓存对象。新建的对象也有可能直接存放进老年代:①.大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。②.大的数组对象,切数组中无引用外部对象。 老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
堆可以存在于物理上不连续的内存空间,只要逻辑上是连续的即可。在实现时,既可以是实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展的来实现的(Xms和Xmx),如果在堆中没有内存完成实例分配,并且堆无法扩展的时候,就会抛出OutOfMemoryError。

方法区:主要用来存储已经被虚拟机加载的类信息,常量,静态变量等数据,即时编译器编译后的代码等数据,是线程共享区域。根据Java虚拟机规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。
运行常量池:是方法区的一部分,Class文件除了有类的版本、字段、方法、接口等描述信息,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行常量池中。

栈:分为本地方法栈和java虚拟机栈,主要用来做方法执行。
Java虚拟机栈:描述的是java方法执行的内存模型:每个方法被执行的时候都会被创建一个“帧栈”用于存贮局部变量表(包括参数),操作栈、方法出口等信息。每个方法被调用,到执行完都对应一个帧栈在虚拟机栈,从入栈到出栈的过程、声明周期与线程相同,是线程私有的。在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。
本地方法栈:基本和虚拟机栈相同,区别的java虚拟机栈为虚拟机执行java服务,本地栈为native方法进行服务。

程序计数器,本地方法栈,java虚拟机栈属于线程私有区,方法区和堆是线程共享区。
程序计数器:最小的一块内存区域,它的作用是当前线程执行字节码的行号指示器,在虚拟机的模型里,字节码解释器就是通过改变这个计数器的值来选取需要执行的下一条的字节码的指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖程序计数器来工作。
由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空(Undefined)。
此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭