首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Java并发编程 理解JVM内存概念模型(一)

介绍

对基本的JVM内存模型的理解非常重要,尤其在开发多线程程序的时候。程序员只有在大脑中建立一个简单清晰的JVM内存概念模型,才能为正确开发多线程程序打下一个良好的基础。

基本的JVM内存模型

上图是一个最简JVM内存概念模型,JVM把它管理的内存大致分为栈内存和堆内存:

栈内存:JVM会为每个线程分配线程栈,线程运行时会使用。随着线程运行时调用方法的不同,线程的运行栈会不断变化。每次一个线程进入一个方法,JVM会为该线程创建新的调用栈(call stack)或称栈帧(stack frame),调用栈上保存线程在该方法上运行要使用的局部变量,这些变量是该线程独有的,其它线程不可见。随着调用方法的嵌套,调用栈也会依次增长,每次执行完一个方法,线程会退出相应的调用栈,相应的内存被JVM释放。

堆内存:是多线程共享的内存区,程序线程运行时创建的引用对象会被分配在堆内存上,包括:

对象类型

原子封装类型(Integer, Double, Long等等)

静态变量类型

注意,当线程在运行时创建对象,引用本身是存在线程自己的调用栈上的,而对象本身则是创建在堆上的。另外,线程之间可以复制对象引用,这样多个线程可以共享堆上的对象数据,但是这个时候可能存在多线程更新数据的可见性(visibility)一致性(consistence)问题。

案例分析

对于上面的代码,我们假设启两个SampleThread线程,当两个线程运行到 方法的中间时,所展示出来的内存图如下图所示:

分析:

栈帧中的 是原子整型局部变量,存在线程栈上。

栈帧中的 是对象引用类型变量,变量本身存在线程栈上,它引用的 实例被分配在堆上。

两个线程同时通过各自的 变量引用共享的 实例。

是静态初始化好(通过 和 关键字)并且被分配在堆上, 静态引用变量也分配在堆上, 实例内部的原子类型字段 和 ,以及原子封装类型对象 和 都是被分配在堆上。

栈帧中的 是原子封装类型,引用本身存在线程栈上,封装对象被分配在堆上,两个线程各一个。

当线程退出 ,其栈帧上的 局部存储被释放,它引用的对象 也成为垃圾待回收。

当线程退出 ,其栈帧上的 和 局部变量存储被释放, 实例因为有静态引用,在程序运行结束前不会被垃圾回收。

结论

JVM大致把内存分为栈内存和堆内存,栈内存是线程的局部存储,而堆内存是线程的共享存储,JVM通过线程栈的方式虚拟多线程并发运行。

对栈内存变量操作不会有多线程问题,但对共享堆上的数据进行并发修改可能会存在可见性和一致性问题。

建立简单的JVM内存概念模型是多线程并发编程的基础,后续我会进一步介绍现代处理器架构和Java内存模型不匹配问题,以及由于这种不匹配而造成的并发编程的坑。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180612G1P1WE00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券