前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 虚拟机运行时数据区

Java 虚拟机运行时数据区

作者头像
lwen
发布2018-04-17 16:12:43
6190
发布2018-04-17 16:12:43
举报
文章被收录于专栏:Java 源码分析Java 源码分析

运行时数据区:

Java 虚拟机的运行时数据区按照大的可以分为线程独立使用的数据区,和所有线程共享的数据区。

一.线程独立使用数据区

1.程序计数器
  1. 程序计数器其实就是 jvm 里面的pc,他指向的都是字节码的偏移量,也就是下一条要执行的字节码
  2. 当然这是 jvm 在执行 java 方法的时候,当程序在执行 navtive 方法的时候这时候起作用的其实是我们物理机上的 pc 此时 jvm 的 pc 是空值(undefine)
  3. 并且这个地方也是所有的 jvm 内存区完全不会抛出 OutOfMemary 异常的位置
2.虚拟机栈
  1. 虚拟机栈其实也就是我们日常所说的堆栈中的栈
  2. 他的生命周期是和当前的线程完全一样
  3. 当在执行一个新的 java 方法的时候他会在 java 虚拟机栈创建一个栈帧。
  4. 栈帧中存放的内容:
    • 局部变量表
    • 操作数栈
    • 动态链接
    • 方法的出入口
  5. 局部变量表是一个非常重要的数据结构这里面存放的主要就是这个 java 方法中的局部变量。而这些变量都是在编译时期确定的。后来会看到其实在 class 中有一个 code 属性,这个属性里面会有一个 Local_max 他的作用就是计算当前的方法需要多少个 Slot ,并且注意这个 Slot 并不是局部变量有多少他就会产生多少,而是根据作用域对这些 Slot 进行复用。(这些都是后面 Class 结构部分需要说的,暂时可以放放)
  6. 局部变量表存放的数据类型除了一些常用 int,float,char,long,short,double,byte 等等还有两个比较特殊的分别是 returnValue 类型和引用类型 reference 类型,reference 类型其实就是我们常说的当我们创建一个对象的时候 jvm 会在栈上创建一个对象的引用,然后真正的对象数据放在堆上。这里的引用就是 reference 类型变量。当然这个引用并不是一定指向的堆中的那个对象还可能指向的是堆中的句柄池中的一个句柄。(后面会详细解释)
3.本地方法栈
  1. 本地方法栈其实就用于执行 Native 方法,也就是本地方法。一般来说 jvm 的规范对这方面没有过多的要求,一般的 jvm 都是直接把本地方法栈和虚拟机栈直接合并了。
  2. 本地方法也就是 Native 方法其实这是 Jvm 对外提供的一个接口,这个接口的作用就是使用 java 的接口去调用其他编程语言写的代码,一般一个 Native 方法里面的方法体不是 java 代码,而是去调用其他的编程语言的代码,也就是此时代码就不归 jvm 来管了,此时调用的什么编程语言就由什么编程语言来管,所以说白了这块内存不完全算是 jvm 的内存。例如说 java 调用了 c++代码这时候的方法堆栈就是 c++的堆栈,jvm 这边应该就是用一个指针指向那块内存。java 的这一特性叫做 JNI (Java Native Interface),其实也不是 java 才有这一特性,很多的编程语言都可以这么玩,例如说在 c++中调用 c 代码其实我们用了 extern 这也是类似的。

二.线程共享数据区

1. 堆
  1. 其实一提到堆我们对他都比较熟悉,也就是我们经常说的和栈结构相对的就是堆了。
  2. 一般来说我们会认为所有的对象都是在堆上开辟的,但是当我们了解了 jvm 内部的一些原理之后我们就应该转变这种观念,其实并非所有的对象都是在堆上开辟的主要是现在的 JIT(Just In Time 即时编译技术) 以及对象逃逸造成部分对象是在栈上开辟的。
  3. 堆目前也是 jvm 进行内存自动管理的部分,GC 堆。
  4. 堆上的内存其实在物理机的内存上不必完全就是连续的。
2.方法区
  1. 方法区其实是一个比较复杂的内存区域,里面存放的内容主要为:
    • JIT 即时编译的代码
    • 静态变量
    • 常量池
    • 加载的类和接口的信息
  2. 这个区域可以看到里面的东西都不是朝生夕死的一些数据,也就是更换的速率不是很频繁,所以对这个区域的 GC 并不是很对,而且这里的 GC 区域比较困难。部分区域的 GC 条件较为苛刻。
3.常量池

​ 常量池其实就是方法区的一部分(当然这是 jdk1.7之前的位置),其实现在(也就是 jdk1.7 以后)java 虚拟机团队把常量池移动到了堆中。这个区域也叫做 “ 永久代 ” (PermGen),但是当前的 jdk1.8 虚拟机团队直接把常量池这个永久代取消了,然后取而代之的叫做元空间(MateSpace)。好吧这里我们还是讨论常量池还存在的情况的吧。之后会专门写关于 jdk1.7 以及1.8 中的做的很大的更改。

​ 其实在 jdk1.7 之前这个地方主要存放的就是 class 字节码中的常量池的内容以及在运行过程中动态生成的常量。尤其是使用的比较多的 String.intern() 方法。这个方法的主要作用就是当程序第一个遇到这个字符串的时候会把他放入常量池中。然后返回常量池中的引用。

4.直接内存
  1. 直接内存是不同于 Native 堆的,因为这个地方主要作用在于进行 NIO 的时候做数据缓冲用的。
  2. NIO 中采用的是通道缓冲区的方式进行 IO 操作的,这里他们为了减少 Java 堆和 Native 堆来回复制数据而采用的一种方式也就是在 java 堆中使用一个 DirectByteBuffer 对象引用这块直接内存然后直接把数据读取到直接内存避免往 Java 堆里面复制。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 运行时数据区:
    • 一.线程独立使用数据区
      • 二.线程共享数据区
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档