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 堆里面复制。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏nnngu

015 反射中的 Class.forName() 与 ClassLoader.loadClass() 的区别

Class.forName() 与 ClassLoader.loadClass() 大家都知道是反射用来构造类的方法,但是他们的用法还是有一定区别的。 在讲区别...

2633
来自专栏武军超python专栏

2018年8月2日魔法方法,异常处理,类属性,类方法,静态方法

今天遇到的新单词: enterprise n企业 ********************************** 魔法方法; 魔法方法:已经具...

1883
来自专栏技术小站

编程填空:第i位替换 编程填空:第i位取反 编程填空:左边i位取反

写出函数中缺失的部分,使得函数返回值为一个整数,该整数的第i位和m的第i位相同,其他位和n相同。

1981
来自专栏电光石火

null或空值的判断处理

1,错误用法一: if (name == "") {      //do something } 2,错误用法二: if (name.equals(""))...

17610
来自专栏小勇DW3

类加载过程中几个重点执行顺序整理

1、 JVM会先去方法区中找有没有相应类的.class存在。如果有,就直接使用;如果没有,则把相关类的.class加载到方法区

2602
来自专栏java学习

Java每日一练(2017/7/7)

1 (单选题)有以下程序片段,下列哪个选项不能插入到行 1 。()。 1. 2.public class A{ 3.//do sth 4. } A publ...

36311
来自专栏转载gongluck的CSDN博客

Lua学习笔记

--Lua笔记-- --0.Lua开篇-- --http://www.cnblogs.com/stephen-liu74/archive/2012/06/11/...

5256
来自专栏mukekeheart的iOS之旅

Java基础——异常体系

在Java中,异常对象都是派生于Throwable类的一个实例,Java的异常体系如下图所示: ?    所有的异常都是由Throwable继承而来,在下一层立...

2767
来自专栏星回的实验室

Angularjs的回调

$q.reject() 方法是在你捕捉异常之后,又要把这个异常在回调链中传下去时使用:

702
来自专栏Java大联盟

Java面试手册:核心基础-3

2.数组有没有length()这个方法? String有没有length()这个方法?

1423

扫码关注云+社区