一个Java类在运行时候,变量是怎么在JVM中分布的呢?
JVM学习第三篇思考:一个Java类在Jvm内存中是怎么存在的
又名:Java虚拟机的内存模型(JMM)是什么样的.
通过前面两篇文章的学习,我们知道了一个Java类的生命周期及类加载器。我们可以得到如下两幅图:
类生命周期:
父类委托机制:
思考:
我们编写的类中的变量、方法、对象这些都需要内存存放的。那么在运行时候这些数据在Java虚拟机内存中是怎么存放的呢?
本文目标:
凯哥(凯哥Java:kaigejava)希望通过本文学习,大家对Java虚拟机运行时数据区域有更深的了解
我们写的代码在JVM中是怎么存在的?
1:我们现在看看总体Java运行时数据模型:
2:我们来看看下面这段代码,执行的时候,在JVM中数据存放:
上面代码很简单,那么对应的变量、对象等在内存中都是怎么分配的呢?
2.1:方法区
注:在JDK1.8之后,方法区被元空间替换了。
方法区:用来存放的是类的信息、常量、静态变量等。该区域也是各个线程共享的内存区域。
根据Java虚拟机规范中的规定,当方法去无法满足内存分配的时候,会抛出:OutOfMemoryError异常的。
根据上面的 定义,我们可以知道比如我们JvmDemo.class信息、static string str=“jvmDemo”是在方法区存放的。
对应咱们代码,方法区存放的如下图:
2.2:堆区
堆区是JVM所管理的内存中的最大的一块区域。该区域是所有线程共享的一块内存区域。该区域空间在虚拟机启动的时候就被创建了(-Xms的设置。后面凯哥(凯哥Java:kaigejava)也会详细讲解的)。
此区域的目的是存放对象实例的。几乎所有的对象实例都是在这里分配的。Java虚拟机规范中是这么描述的:所有的对象的实例以及数组都要在堆上分配。
堆区是垃圾收集器管理的主要区域(后面凯哥(凯哥Java:kaigejava)也会详细讲解的).
堆区空间,在物理上可以不是连续的内存空间,只要在逻辑上是连续的即可。如果堆没有内存完成实例分配,并且堆也无法在扩展的时候,将会抛出异常:OutOfMemoryError。这个大家很熟悉吧。
根据上面定义的,我们可以知道,上面代码中Son son = new Son(); 这行代码创建的实例对象是存放在堆区的。
2.3:程序计数器
程序计数器的作用可以看做是当前线程所执行的字节码的行号指示器。字节码解释器在工作的时候,时候通过改变计数器的值来选择接下来要执行的字节码指令的。
同时我们都知道,当多线程的时候,Java虚拟机是通过线程轮流切换分配处理器执行时间的方式来实现的。在任何一个确定的时刻一个处理器只会执行一条线程中的指令。因此,为了解决多个线程在切换后,能够迅速恢复到切换前执行的位置,每个线程都需要有个独立的程序计数器,各个线程直接的计数器互不影响,独立存储的。一般称这类内存区域为:"线程私有"的内存。当线程正在执行的一个方法是Native的,这种情况下,计数器的值就是undefined了。这个区域也是Java虚拟机内存区域中唯一一个没有OOM的区域。
根据上面描述,我们可以知道,我们自己编写的*.java文件要想被执行,需要被编译成*.class的字节码文件。字节码文件对应各种字节码指令。比如我们上面JvmDemo的字节码文件:
从上面截图,我们可以看到,行号是0,3,4,7,8这样的。程序计数器就是记录这些行号的
我们也可以使用idea的插件,来查看我们JvmDemo的相关信息:
2.4:虚拟机栈
Java虚拟机栈,也是线程私有的。其生命周期与线程相同,当一个线程运行结束后,对应的虚拟机栈也结束。
虚拟机栈是Java方法执行的内存模型:即每个方法被执行的时候,都会被同时创建一个栈帧(Stack Frame),这个栈帧是用来存放方法局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直到其执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。
比如:我们上面代码执行的时候,执行main方法的时候,主线程就会把main方法压入到虚拟机栈中,当执行到add方法的时候,add方法就被压入到栈中了。当执行完add方法后,add方法就被从虚拟机栈中弹出,这个时候add对应的栈帧也销毁。
虚拟机栈帧如下图:
局部变量存放:各种基本数据类型、对象引用和返回类型
八大基本数据类型:boolean、byte、char、short、init、float、long、double;
对象引用:reference类型。这里是存放的是对象在对内存中的地址值。不等同于对象自身的。根据不同的虚拟机的实现,这个指向可能是指向了对象起始地址的引用指针,也有可能是指向了对象对象的句柄或其他对象与其他对象的位置;
返回类型:returnAddress类型。指向一条字节码指令地址。
扩展:long类型和double类型的数据会占用2个局部变量空间。其他6个数据类型占用1个。
局部变量表所消耗的内存空间在编译期间就完成了分配,当进入一个方法的时候,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的。在方法的运行期间,不会改变该区域空间大小的。
在咱们上面代码中,虚拟机栈存放的就是咱们main方法和add方法相关的
2.5:本地方法栈
本地方法栈的作用和虚拟机栈的作用相似。不同之处在于:虚拟机栈是为了虚拟机执行Java方法服务的。而本地方法栈则是为了虚拟机使用到Native方法服务的。此区域也是方法私有的。比如我们调用线程的run方法或者CAS的时候,调用的都是native方法。
总结:
通过本文学习,我们在自己脑海中应该有如下图的概念:
其中方法区、堆区是所有线程共享的;虚拟机栈、程序计数器、本地方法栈这三个是线程私有的,其生命周期同线程一致。
方法区:存放类型、常量、静态变量等
堆区:用来存放对象实例、数组
虚拟机栈:局部变量表、动态链接、操作栈等
本地方法栈:用来存放当线程调用native方法的时候使用的
程序计数器:用来记录当前线程执行的字节码行号的。
好了,本文凯哥(凯哥Java:kaigejava)就和大家唠唠在运行时候Java虚拟机的数据区域。在下篇文章中,咱们在详细唠唠堆区。
一个Java类在运行时候,变量是怎么在JVM中分布的呢?的更多相关文章
- 假如java类里的成员变量是自身的对象
假如java类里的成员变量是自身的对象,则新建该类对象时内存中怎么分配空间,我感觉似乎死循环了. 不过我想的肯定是错的,因为很多类的成员变量是自身对象,并且绝对无错,举个例子: Class A{ pr ...
- java类里的成员变量是自身的对象问题
今晚看单例模式饿汉时想到一个问题:假如java类里的成员变量是自身的对象,则新建该类对象时内存中怎么分配空间,我感觉似乎死循环了.于是上网搜索了下,哈哈,果然有人早就思考过这个问题了,站在巨人的肩膀上 ...
- 如何唯一确定一个 Java 类?
今天偶然想起之前和朋友讨论过的一个问题:如何唯一确定一个 Java 类?我相信大多数朋友遇到这个问题的回答都是:类的全路径呗.但事实上,唯一确定一个 Java 类,单单靠类路径是不够的,还要多加上一个 ...
- 第一次尝试学习java 安装jdk 与配置环境变量 写第一个java程序 并运行
第一次学习java,今天知道了java之父叫 詹姆斯.高司令 其它的记不住太多,首先我们先来安装jdk 百度搜索jdk12 (现在的jdk为12版本)安装稳定版 找到javaSE12X.. 下 ...
- 测试 Java 类的非公有成员变量和方法
引言 对于软件开发人员来说,单元测试是一项必不可少的工作.它既可以验证程序的有效性,又可以在程序出现 BUG 的时候,帮助开发人员快速的定位问题所在.但是,在写单元测试的过程中,开发人员经常要访问类的 ...
- JAVA类与对象---实例变量与类变量的区别,实例方法和类方法的区别
实例变量 实例变量声明在一个类中,但在方法.构造方法和语句块之外: 当一个对象被实例化之后,每个实例变量的值就跟着确定: 实例变量在对象创建的时候创建,在对象被销毁的时候销毁: 实例变量的值应该至少被 ...
- 1--我们写了一个java类,那么生成一个对象占用多大的内存?
public class Student { private long id; private long userId; private byte state; private long create ...
- mac os intellij如何快路查看一个java类的所有方法,结构
如果是自己写的java类,点击点击导航的project-setting-show members 如果是系统库的,点击structure 再点一下lib中的类,或者快捷键 command+F12
- 【Java.Regex】使用正则表达式查找一个Java类中的成员函数
代码: import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; imp ...
- 使用log4j使某些java类的日志信息输出到指定日志文件中
Log4j 是 Apache 的一个开放源代码项目,通过使用 Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI 组件.甚至是套接口服务器.NT 的事件记录器.UNIX Syslog ...
随机推荐
- AT_joisc2019_j 题解
先考虑这个式子: \[\sum_{j=1}^{M} |C_{k_{j}} - C_{k_{j+1}}| \] 一定是在 \(C\) 有序时取到,具体证明很简单各位读者自己证明. 那么现在式子变成: \ ...
- P9196 题解
来一份线性时间的题解. 考虑先解决前缀限制,显然可以直接把字符串和询问全部搬到 Trie 树上,问题就变成了查询一个子树内满足后缀限制的字符串数量. 接着考虑 Trie 树合并,具体地,把后缀限制以及 ...
- SpringBoot 处理xss攻击
添加依赖 <!-- xss跨站脚本攻击 --> <dependency> <groupId>net.dreamlu</groupId> <arti ...
- yb课堂 前端项目通用底部选项卡 CommonsFooter 《三十六》
学会看cube-UI文档,并掌握cube-tab-bar开发 前端需求分析 底部导航 首页Banner 首页视频列表 视频详情模块 注册模块 登陆模块 个人信息模块 下单模块 订单列表模块 文档地址: ...
- yb课堂实战之播放记录表设计和模块开发 《十五》
play_record表设计 DROP TABLE IF EXISTS `play_record`; CREATE TABLE `play_record` ( `id` int(11) NOT NUL ...
- [大数据][机器学习]之Model Card(模型卡片)介绍
每当我们在公有云或者私有云发布训练好的大数据模型,为了方便大家辨识.理解和运用,参照huggingface所制定的标准制作一个Model Card展示页,是种非常好的模型展示和组织形式. 下面就是一个 ...
- SQL Thinking
s2下半年我在内部有一次部门级别的技术分享会,以本文内容分享为主. 其实有很多人问过我相同的问题,遇到需要改写的慢sql,不知道怎么改,改好了以后也不知道等不等价?不等价了也不知道错在哪?这个要怎么破 ...
- [oeasy]python0003_ 终端大冒险_终端命令_whoami_pwd_ls
终端大冒险_终端命令_ls_pwd_whoami 回忆 上次 了解基本环境 简称 含义 CLI 命令行界面 GUI 图形用户界面 在 CLI 中 通过终端 连接 远程服务器的 壳(shell) 控制 ...
- oeasy教您玩转linux 010211 牛说 cowsay
我们来回顾一下 上一部分我们都讲了什么? 软件包工具是 apt 软件包不但能下载,也能升级,还能删除 专门管理软件包的 aptitude 这次我们下载个牛说 cowsay: sudo apt inst ...
- oeasy教您玩转vim - 51 - # 读写文件
读写文件 回忆上节课内容 命令行的光标控制 方向键️️️️️可以控制左右移动 shift+️️️️️按照word左右移动光标 ctrl+b 到开头begin ctrl+e 到结尾end ctrl+w ...