博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java内存结构
阅读量:4150 次
发布时间:2019-05-25

本文共 1983 字,大约阅读时间需要 6 分钟。

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

    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内存结构中的各个模块的分析,如有问题,欢迎指正~

参考:

          

         

         

    

你可能感兴趣的文章
实现包含min,max,push,pop函数的栈
查看>>
实验2-6 字符型数据的输入输出
查看>>
实验3-5 编程初步
查看>>
实验4-1 逻辑量的编码和关系操作符
查看>>
实验5-2 for循环结构
查看>>
实验5-3 break语句和continue语句
查看>>
实验5-4 循环的嵌套
查看>>
实验5-5 循环的合并
查看>>
实验5-6 do-while循环结构
查看>>
实验5-7 程序调试入门
查看>>
实验5-8 综合练习
查看>>
第2章实验补充C语言中如何计算补码
查看>>
深入入门正则表达式(java) - 命名捕获
查看>>
使用bash解析xml
查看>>
android系统提供的常用命令行工具
查看>>
【Python基础1】变量和字符串定义
查看>>
【Python基础2】python字符串方法及格式设置
查看>>
【Python】random生成随机数
查看>>
【Python基础3】数字类型与常用运算
查看>>
Jenkins迁移jobs
查看>>