JVM进阶之运行时数据区

8 篇文章 0 订阅
6 篇文章 5 订阅

前言

  最近在看重温JVM相关的知识点,但总感觉看书很枯燥乏味,看别人的博客知识又显得零碎,知识体系不够系统,所以有必要把所见所闻所学的点,好好地梳理成文,加强自己理解程度的同时,挖掘自身的盲点。好了,鸡血不宜多,让我们开始JVM的新篇章。

  话说平时开发中的我们有曾想过写过的代码运行在哪儿,比如在类中声明了static类型的变量,在方法中new了一个对象等等……如果这些都不了解,我只能说不是个合格的码农。再一个线上环境出现的JVM性能问题,比如卡顿,吞吐量低,请求延迟高等问题时,光是会写代码完全无从下手解决问题。怎么去解决生产环境里出现的各种“奇葩”问题?今天先讲讲代码中的变量、对象、类信息等在JVM中的存在。

运行时数据区

计算机中的程序运行在硬件上,无非是数据与指令相互作用,共同协调得完成某件事情。在JVM中也不例外,所以这里我将JVM的内存区域按功能分为数据区和指令区(这里的指令区其实也是数据),看图:
image

  • 数据区:方法区和堆
  • 指令区:程序计数器、虚拟机栈和本地方法栈

咱们一个个来

程序计数器

  程序计数器记录的是当前线程正在执行的字节码指令的地址,可以比作当前线程所执行的字节码的行号指示器,需要注意的地方是执行Native方法时,计数器的值就是空的。每个线程都有独立的程序计数器,所以计数器属于线程私有的一小块内存。

虚拟机栈

  虚拟机栈存储的当前线程运行方法所需要的数据、指令、返回地址。即每个方法在执行的同时都会创建一个栈帧存储局部变量、操作数栈、动态链接、方法出口等信息。方法的调用到完成就对应栈帧的入栈和出栈的过程。
  如果线程请求的栈深度大于虚拟机所允许的深度,程序将栈溢出(StackOverflowError)异常。
  很明显,虚拟机栈也是线程独享的内存空间。

本地方法栈

  本地方法栈存储调用本地方法(native)所需要的数据指令,区别于虚拟机栈的普通方法。也是线程私有的空间。

方法区

此区域JDK1.8已移除,替代的是metaspace,本文暂不纠结。

  方法区用于存储虚拟机加载的类信息、常量、静态变量、JIT即时编译的代码(如动态代理生成的类信息)等数据,这些数据共同特点是难以改变,而且对象存活时间长。在GC分代中,方法区又称为永久代,后续的文章会有介绍。
  显而易见,类信息等等数据都不会只属于某一个线程,所以是线程共享的区域。当方法区无法满足内存分配资源时,会抛出OutOfMemoryError异常。

  堆唯一的目的就是存放对象的实例,比如new产生的对象,所有的对象以及数组都要在堆上分配内存,所以堆中的内存自动管理机制尤为重要。需要注意的是堆与方法区存放对象的区别是对象的存活时期不同,堆中98%对象属于朝生熄灭的对象,至于对象是怎么被回收的,后续再讲。
  堆中没有内存分配给对象实例时,也会抛出OOM异常。属于线程共享的区域。

按照是否被线程共享的角度来看,如下图:
image

  • 上图很好的说明了线程与各区域的关系
  • 程序计数器、虚拟机栈和本地方法栈属线程私有,随着线程而生,也随着线程而死
  • 方法区和堆属于线程共享的区域,既然共享了就容易出现数据竞争等线程安全问题,并发安全也主要是解决堆中对象数据安全

好了,这篇文章算是简单的梳理了java对象、变量、类信息等在JVM内存区域的存储位置,但前提是在程序运行时才有的数据区。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值