第一章 JVM 内存模型

Java 虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是:程序计数器

Java 虚拟机栈

本地方法栈

方法区。

下面对这五个区域展开深入的介绍。

1.1 程序计数器

1.1.1 什么是程序计数器?

程序计数器是一块较小的内存空间,可以把它看作当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的那一条字节码指令的地址。

注:但是,如果当前线程正在执行的是一个本地方法,那么此时程序计数器为空。

1.1.2 程序计数器的作用

程序计数器有两个作用:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。

在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

1.1.3 程序计数器的特点是一块较小的存储空间

线程私有。每条线程都有一个程序计数器。

是唯一一个不会出现OutOfMemoryError的内存区域。

生命周期随着线程的创建而创建,随着线程的结束而死亡。

1.2 Java虚拟机栈(JVM Stack)

1.2.1 什么是Java虚拟机栈?

Java虚拟机栈是描述Java方法运行过程的内存模型。

Java虚拟机栈会为每一个即将运行的Java方法创建一块叫做“栈帧”的区域,这块区域用于存储该方法在运行过程中所需要的一些信息,这些信息包括:局部变量表 存放基本数据类型变量、引用类型的变量、returnAddress类型的变量。

操作数栈

动态链接

方法出口信息

当一个方法即将被运行时,Java虚拟机栈首先会在Java虚拟机栈中为该方法创建一块“栈帧”,栈帧中包含局部变量表、操作数栈、动态链接、方法出口信息等。当方法在运行过程中需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中。

当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。

注意:人们常说,Java的内存空间分为“栈”和“堆”,栈中存放局部变量,堆中存放对象。

这句话不完全正确!这里的“堆”可以这么理解,但这里的“栈”只代表了Java虚拟机栈中的局部变量表部分。真正的Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

1.2.2 Java 虚拟机栈的特点

(1)局部变量表的创建是在方法被执行的时候,随着栈帧的创建而创建。而且,局部变量表的大小在编译时期就确定下来了,在创建的时候只需分配事先规定好的大小即可。此外,在方法运行的过程中局部变量表的大小是不会发生改变的。

(2)Java 虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError。a) StackOverFlowError: 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。

b) OutOfMemoryError: 若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。

(3)Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。注:StackOverFlowError和OutOfMemoryError的异同?

StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。

1.3 本地方法栈

1.3.1 什么是本地方法栈?

本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法区是本地方法运行的内存模型。

本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

方法执行完毕后相应的栈帧也会出栈并释放内存空间。

也会抛出StackOverFlowError和OutOfMemoryError异常。

1.4 堆

1.4.1 什么是堆?

堆是用来存放对象的内存空间。 几乎所有的对象都存储在堆中。

1.4.2 堆的特点

(1)线程共享

整个 Java 虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java 虚拟机栈、本地方法栈都是一个线程对应一个的。

(2)在虚拟机启动时创建。

(3)垃圾回收的主要场所。

(4)可以进一步细分为:新生代、老年代。

新生代又可被分为:Eden、From Survior、To Survior。不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。

(5)堆的大小既可以固定也可以扩展,但主流的虚拟机堆的大小是可扩展的,因此当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出 OutOfMemoryError。

1.5 方法区

1.5.1 什么是方法区?

Java 虚拟机规范中定义方法区是堆的一个逻辑部分。方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。

1.5.2 方法区的特点线程共享 方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享的。整个虚拟机中只有一个方法区。

永久代 方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。

内存回收效率低 方法区中的信息一般需要长期存在,回收一遍内存之后可能只有少量信息无效。 对方法区的内存回收的主要目标是:对常量池的回收 和 对类型的卸载。

Java虚拟机规范对方法区的要求比较宽松。 和堆一样,允许固定大小,也允许可扩展的大小,还允许不实现垃圾回收。

1.5.3 什么是运行时常量池?

方法区中存放三种数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。

我们一般在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。

当这个类被Java虚拟机加载后,class文件中的常量就存放在方法区的运行时常量池中。而且在运行期间,可以向常量池中添加新的常量。如:String类的intern()方法就能在运行期间向常量池中添加字符串常量。

当运行时常量池中的某些常量没有被对象引用,同时也没有被变量引用,那么就需要垃圾收集器回收。

1.6 直接内存

直接内存是除Java虚拟机之外的内存,但也有可能被Java使用。

在NIO中引入了一种基于通道和缓冲的IO方式。它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需先将外面内存中的数据复制到堆中再操作,从而提升了数据操作的效率。

直接内存的大小不受Java虚拟机控制,但既然是内存,当内存不足时就会抛出OOM异常。

1.7 综上所述Java虚拟机的内存模型中一共有两个“栈”,分别是:Java虚拟机栈和本地方法栈。 两个“栈”的功能类似,都是方法运行过程的内存模型。并且两个“栈”内部构造相同,都是线程私有。 只不过Java虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈是描述Java本地方法运行过程的内存模型。

Java虚拟机的内存模型中一共有两个“堆”,一个是原本的堆,一个是方法区。方法区本质上是属于堆的一个逻辑部分。堆中存放对象,方法区中存放类信息、常量、静态变量、即时编译器编译的代码。

堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器主要的工作区域。

程序计数器、Java虚拟机栈、本地方法栈是线程私有的,即每个线程都拥有各自的程序计数器、Java虚拟机栈、本地方法栈。并且他们的生命周期和所属的线程一样。 而堆、方法区是线程共享的,在Java虚拟机中只有一个堆、一个方法栈。并在JVM启动的时候就创建,JVM停止才销毁。

第二章 揭开Java对象创建的奥秘

2.1 对象的创建过程

当虚拟机遇到一条含有new的指令时,会进行一系列对象创建的操作:

(1)检查常量池中是否有即将要创建的这个对象所属的类的符号引用;若常量池中没有这个类的符号引用,说明这个类还没有被定义!抛出ClassNotFoundException;

若常量池中有这个类的符号引用,则进行下一步工作;

(2)进而检查这个符号引用所代表的类是否已经被JVM加载;若该类还没有被加载,就找该类的class文件,并加载进方法区;

若该类已经被JVM加载,则准备为对象分配内存;

(3)根据方法区中该类的信息确定该类所需的内存大小;

一个对象所需的内存大小是在这个对象所属类被定义完就能确定的!且一个类所生产的所有对象的内存大小是一样的!JVM在一个类被加载进方法区的时候就知道该类生产的每一个对象所需要的内存大小。

(4)从堆中划分一块对应大小的内存空间给新的对象;分配堆中内存有两种方式:指针碰撞 如果JVM的垃圾收集器采用复制算法或标记-整理算法,那么堆中空闲内存是完整的区域,并且空闲内存和已使用内存之间由一个指针标记。那么当为一个对象分配内存时,只需移动指针即可。因此,这种在完整空闲区域上通过移动指针来分配内存的方式就叫做“指针碰撞”。

空闲列表 如果JVM的垃圾收集器采用标记-清除算法,那么堆中空闲区域和已使用区域交错,因此需要用一张“空闲列表”来记录堆中哪些区域是空闲区域,从而在创建对象的时候根据这张“空闲列表”找到空闲区域,并分配内存。 综上所述:JVM究竟采用哪种内存分配方法,取决于它使用了何种垃圾收集器。

(5)为对象中的成员变量赋上初始值(默认初始化);

(6)设置对象头中的信息;

(7)调用对象的构造函数进行初始化;

此时,整个对象的创建过程就完成了。

虚拟机 java 开发_深入浅出 Java 虚拟机 · 通往高级 Java 开发的必经之路相关推荐

  1. 通往高级 Java 开发的必经之路

    一.JVM 内存模型 Java 虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: 程序计数器: Java 虚拟机栈: 本地方法栈: 堆: 方法区. 下面对这五 ...

  2. java11模块化开发_【JDK 11】关于 Java 模块系统,看这一篇就够了

    继 2014 年 3 月 Java 8 发布之后,时隔 4 年,2018 年 9 月,Java 11 如期发布,其间间隔了 Java 9 和 Java 10 两个非LTS(Long Term Supp ...

  3. 移动硬盘设置java变量_移动硬盘Linux内搭建MyEcilipse8.6开发环境

    还是在去年的时候,买了一个西数WD 3200BEV的320GB移动硬盘,闲来没事瞎折腾,在移动硬盘上安装了个Linux系统,在我的台式机和朋友的笔记本上运行成功,现在已经安装好了MyEcilipse8 ...

  4. 第三方工具监控java进程_前9个免费的Java进程监视工具以及如何选择一种

    第三方工具监控java进程 这样就可以运行Java代码了. 也许它甚至可以在生产服务器上运行. 当您做好工作后,我们得到了好消息和令人讨厌的消息. 令人讨厌的消息是,现在开始调试. 就是进行调试和应用 ...

  5. 基础贴吧java代码_原来你是这样的JAVA[01]-基础一瞥

    1.Java是什么呢? Java不仅是一门语言,而且是一个完整的平台,有一个庞大的库,其中包含了很多可重用的代码和一个提供安全性.跨操作系统的可移植性以及自动垃圾收集等服务的执行环境. 2.JDK 和 ...

  6. java安装_如何在 Mac 上安装 Java | Linux 中国

    macOS 用户可以运行 Java 的开源版本,以及用于云原生开发的新框架. 来源:https://linux.cn/article-12393-1.html 作者:Daniel Oh 译者:MCGA ...

  7. 零基础可以学习java吗_零基础真的可以学习java吗?

    Java是一个比较抽象的开发语言,涉及知识点比较多,如果自学的话,可以按照五个阶段来学习,先学好基础知识,再逐步扩展,由易到难.要注意视频和书本内容相辅相成,切记不要只看视频而不忽略书本基础的知识要点 ...

  8. 用控制台怎么编译java程序_怎么在cmd中运行java控制台程序?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 2010-08-07  17:00             1,111 SendGift.java 2010-08-09  17:40           ...

  9. github热门java项目_盘点Github上热门的Java开源项目

    4月份GitHub上最热门的Java开源项目排行已经出炉啦,本月的榜单都被Spring相关的项目占领了,一起来看看上榜详情吧! 1. spring-boot-demo https://github.c ...

最新文章

  1. 实战并发编程 - 01多线程读写同一共享变量的线程安全问题深入剖析
  2. Spring学习1之ioc
  3. 机器学习碎碎念:霍夫丁不等式
  4. Android 6.0 超级简单的权限申请2 (Permission)
  5. 【转载】创建型-工厂方法模式
  6. KMS的几个开源实现汇总
  7. 使用git将code同时提交github,gitee,coding
  8. php实现一个简单的购物网站
  9. DB2 SQL Error: SQLCODE=-803, SQLSTATE=23505, SQLERRMC=2 (转载)
  10. MSDN Windows 10 21H1 64位19043原版系统
  11. eclipse使用git合并_Eclipse的git插件冲突合并方法
  12. 微型计算机是嵌入式吗,什么是嵌入式计算机
  13. 10月24日——程序猿的节日
  14. Visual Studio 插件番茄助手2个优秀的特性
  15. 在厉害的圈子里耳濡目染 No.110
  16. FairGuard游戏Lua加密方案解析
  17. 量子逻辑电路的初步探索
  18. Typescript.中文.接口声明.lib.es5.d.ts
  19. 再度升级:深入分析针对金融科技公司的Evilnum恶意软件及组件
  20. Predict Binding Sites of Transcription Factor 富集分析

热门文章

  1. 计算机科学技术的教育应用论文,浅谈计算机科学技术在计算机教学中的应用论文...
  2. 台式计算机欢迎界面下不去,Win7系统开机不显示欢迎界面的方法
  3. spark官方文档_这些未在 Spark SQL 文档中说明的优化措施,你知道吗?
  4. 街机linux有安卓好吗,Ubuntu下用xmame玩街机游戏
  5. 【完成发布】Lazy Line Painter – 非常有趣的 jQuery 路径动画插件
  6. vue结合ueditor富文本编辑器(换肤分离)
  7. React Native面试知识点
  8. iOS开发 之 可穿戴设备 蓝牙4.0 BLE 开发
  9. java 动态增加定时任务
  10. android BluetoothAdapter蓝牙BLE扫描总结