jvm内存模型总结

JVM内存模型

之前看过很多关于jvm内存模型的文章,什么有堆栈,方法区,程序计数器等划分,也有文章说主存和工作内存的模型。
这里我觉得无论是jvm内存区域的划分,还是主存工作内存的使用,都是属于jvm内存模型内的知识。基于自己的理解,简单总结一下,单纯只是个人总结,不一定是正确的,假如看到有错误的地方可以帮忙指出。

一、jvm运行期的内存区域划分:

这里写图片描述

上述图可以比较直观的看出jvm运行期,哪些内存区域属于共享的,哪些属于线程私有的。下面简单的介绍每个内存区域:

1.线程私有的内存区域:

(1)java 栈(jvm stack)
主要存放一个个栈帧,每个栈帧对应着线程执行每个方法相关的数据(局部变量表,操作栈,动态链接,方法出口等信息),每一个方法执行完了,对应的栈帧就会从java栈出栈。当栈的深度达到jvm所允许的最大深度,就会抛出 stackoverflowerror 的错误,当扩展无法申请到足够的内存则会抛出 outofmemoryerror 的错误。
(2)程序计数器(PC register)
很小的内存空间,因为jvm底层执行程序是执行字节码指令,而程序计数器就记录着当前指令的执行位置。随着指令执行而变化,从而获取下一个需要执行的指令(可实现分支,循环,跳转,异常)。
(3)本地方法栈(native method stack)
与java栈存储内容很相似,只是java栈是服务于java方法(字节码),而本地方法栈是服务于native方法。同样也会抛出上面提到的异常错误。

2.线程共享的内存区域:

(1)堆(heap)
这一块主要是存放对象数据,是jvm内存中最大的一块。包含了新生代和年老代,也是GC(垃圾回收)主要收集的区域。(GC算法会在后面的文章里提到),当内存申请超过了jvm定义的内存大小,则会报outofmemory的错误。
(2.1)本地方法区(Method Area)
主要存放的是类信息,常量,静态变量等数据,在jdk1.8之前,hotspot里是将方法区当做永久代来使用,之后废除了永久代,这里会在另外一篇文章里解释。
(2.2)运行时常量池(Runtime Constant Pool)
属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用,如字符串,final变量,类名和方法名常量等(这里需要注意常量池的常量的存储大小)

二、主存和工作内存:

与内存区域划分不在同一个层面上,jvm中的所有变量都是存放在主存中,所有线程在获取这些变量的时候,首先需要将变量拷贝一份到自己的工作内存中,然后再在工作内存对这些变量进行操作。不同线程无法访问彼此的工作内存中的变量。
这里写图片描述

因此假如A线程想要修改某个变量test1,首先将线程的工作内存中的变量赋值,然后再将变量传递到主存上去。
这样的模型,假如是线程操作私有的变量是没有问题的,假如是线程操作共享的变量,可能就会引起操作结果有误。比如当线程A将共享变量test2拷贝到A的工作内存,这个时候B线程也拷贝了test2到B的工作内存,当A操作完test2经过flush将值刷到主存后,B线程操作完test2同步到主存的时候,会将A的操作覆盖掉。
这样的问题就是同步问题。同步问题可以通过synchronized锁或者volatile来实现。(如何实现同步将会在另外的文章里讲述

后续有补充,会持续更新。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值