Java内存结构

     这篇文章尽量将每个区域的作用,以及特点描述清楚,直到他们会在什么时候用到,关于其相关的概念,暂不做展开分析

    java内存结构由以下几个部分组成

        程序计数器

        堆

        本地方法栈

        虚拟机栈(也叫java栈)

        方法区

接下来就主要介绍每个区的是干什么的,以及有什么作用

程序计数器

    用来保存当前线程执行的虚拟机字节码的指令地址,通过改变字节码计数器的值,来获取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复都依赖于这个计数器来完成,多线程情况下,为了线程切换后能恢复到正确的执行位置,每个线程都拥有一个程序计数器。

    如果当前线程执行的是一个本地方法,那么计数器当中保存的是undefined

    每个线程对应一个程序计数器,随着线程的创建而创建,线程的结束而销毁,唯一一个不会出现outOfMemoryError的区域

Java虚拟机栈

    java虚拟机栈也是和线程相关联的,每创建一个线程就对应一个java虚拟机栈,每个java虚拟机栈当中对应多个栈帧,每调用一个方法就会往栈当中压入一个栈帧,栈帧是用来存储方法中涉及到的数据信息,每个方法调用到执行结束,就是一个栈帧入站到出站的过程。

    java虚拟机栈顶中永远是当前正在执行的方法,如果在这个栈帧中调用另外一个方法,与之对应的栈帧也会被压入栈内,变为当前活动的栈帧,方法执行结束之后,将栈帧移除栈中,将方法的返回值作为当前活跃的栈帧的操作数,如果没返回值,新活动的栈帧当中操作数不会发生变化,

    每个栈帧当中存储的有:局部变量表,操作数栈,方法连接,方法返回地址。 局部方法表用来存储方法当中的局部变量,在编译时期,就会确定大小,在执行的时候只需分配大小即可,方法运行过程中,局部方法表大小不会发生变化

    虚拟机栈会有两种类型错误,StackOverFlowError和OutOfMemoryError,StackOverFlowError,如果java虚拟机栈的大小不允许动态扩展,当线程请求栈的深度超过java虚拟机栈的最大深度时,就会抛出异常。OutOfMemoryError是,如果允许动态扩展,当线程请求栈时,内存用完了,就会抛出OutOfMemoryError错误了

本地方法栈

    本地方法栈(native method stack)和java虚拟机栈类似,不过是为native方法服务的,

    本地方法栈,在执行本地方法时,也会把当前执行的方法作为栈帧压入栈中,同样也会抛出StackOverFlowError和OutOfMemoryError错误。

    是java存储对象的地方,是jvm当中最大的一块地方,也是垃圾回收的主要场所,堆对于所有线程来说都是共享的,进一步可以分为新生代(Eden区 from Survior和to Survior)和老年代, 在虚拟机启动时创建

    堆的大小是可以动态分配的,当线程请求分配内存,但是堆已经满了时,且内存无法扩展时,就会抛出OutOfMemoryError

    堆中分配内存有两个实现方式

         1、指针碰撞法

             前提是堆中内存都是连续的,已经使用的内存和未使用的内存在不同侧,通过一个指针作为临界点,当需要分配内存时,只需要把指正往空闲的一端移动需要分配内存大小的长度即可

         2、空闲列表法

              堆当中的数据并不是完整的,已经分配的和未分配的都交互存在的,JVM当中会维护一个列表,来记录维护的空闲内存信息,当分配操作发生的时候,分配一块内存给对象实例,然后更新空闲列表数据。在多线程下,需要考虑并发问题。

          解决办法

          a:采用CAS保证数据更新的原子性

          b:将内存分配的行为按照线程划分,每个线程在堆中分配一块大的区域,叫做本地线程分配缓冲(Local Thread Alloctation Buffer, LTAB)

方法区

    方法区和堆一样,是可以被线程共享的一块区域,主要是用来存储已经被虚拟机加载类信息,常量,静态变量,及时编译器编译后的代码。

    关于方法区的垃圾回收:方法区主要是来回收常量池和类的卸载,一般来说方法区的数据需要长期存在,属于堆的逻辑分区,按照堆当中划分的方式,方法区会被称作是“老年代”。方法区的实现是比较宽松的,可以固定大小,也可以动态扩展,也可以不垃圾回收。同样的,当内存分配不能被满足时,也会抛出OutOfMemoryError错误。

--------------------------------------------------------------------

最后,需要了解下运行时常量池,即方法区当中的一部分,

运行时常量池

    主要是用来存放编译时各种常量,包括字面值和符号引用,当然在运行期间也可以往常量池当中增加新的常量,比如String.intern()

 

以上就是java内存结构中的各个模块的分析,如有问题,欢迎指正~

参考:JVM 内存结构

          JVM内存结构分析

         jvm系列(二):JVM内存结构

         一点一滴探究 JVM 之内存结构

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值