JVM复习

冯诺依曼模型与计算机处理数据过程相关联:

  • 冯诺依曼模型:        
    • 输入/输出设备
    • 存储器
    • 输出设备
    • 运算器
    • 控制器
  • 处理过程:
    • 提取阶段:输入设备传入原始数据,存储到存储器
    • 解码阶段:由CPU的指令集架构ISA将数值解码成指令
    • 执行阶段:控制器把需要计算或处理的数据调入运算器
    • 最终阶段:由输出设备把运算结果返回

所以JVM是什么呢?

  • 首先,将java文件编译成.class文件之后,JVM会对字节码文件进行解释,翻译成对应平台的机器指令开始执行。屏蔽了底层操作系统,实现跨平台运行。

.java文件是如何变成.class文件的?

类文件解读:

  • 16进制

  • magic、版本号、常量池(62个字面量和符号引用)、字段表集合、方法表集合

  • 符号引用就是类信息、修饰符,名称等等,不直接指向

类加载机制:

所谓的类加载机制就是将class文件加载进内存,并对数据进行校验,转换解析和初始化,形成JVM可以直接使用。

  • 当字节码文件加载到内存的时候,是不是需要一个访问入口呀?
  • 那如何将字节码文件加载进内存呢?
    • 常见的从本地系统加载
    • 动态代理技术,运算时计算而成
    • 从jar包中加载
  • 类加载过程:
    • 装载:
      • 通过类全限定名获取类的二进制字符流!
      • 将字符流代表的静态存储结构转换为方法区的运行时数据结构
      • 在堆中生成java.lang.class对象,作为对方法区中这些数据的访问入口
    • 链接
      • 验证:格式验证、字节码验证、符号引用验证。-Xverify:none 取消验证。
      • 准备:为静态变量赋值,初始化成默认值。
        • 这里不包含final修饰的static,final修饰的static都在编译的时候就分配了
        • 不会为实例变量分配初始化,类变量在方法区中,实例变量随着对象在堆中(即在实例构造器方法中进行的)
      • 解析
        • 将符号引用转换成直接引用,直接指向目标的指针,或者间接定位到目标的句柄
        • 对解析结果进行缓存
    • 初始化
      • 执行类构造器方法的过程,对比于准备阶段,这里是通过指定主观计划去初始化变量和其他资源。
      • 对类变量设置初始值的两种方式:
        • 直接声明
        • static代码块
      • 步骤
        • 先装载和链接本类
        • 然后初始化父类
        • 初始化自己
      • 什么时候初始化:(主动引用)
        • 创建实例;
        • 对静态变量赋值;
        • 调用静态方法;
        • 调用子类父类也会初始化;
        • 标明启动类的类
      • (被动引用)
        • 定义类数组不会初始化
        • 使用父类的静态变量,不会初始化
        • static final不会初始化
    • 卸载:
      • 用完之后就卸载回收
        • 包括类加载器,class对象,实例
  • 类加载器:
    • 就是读取字节码,转换成java.lang.class类的一个实例的代码模块
    • 一个类在同一个类加载器中具有唯一性,不同类加载器是允许同名类存在的,类加载器不同,就不会是同一个类。
    • 分类:
      • bootstrap classloader:负责java_home的所有class
      • extension classloader:负责一些扩展的包
      • app classloader:classpath中指定的包
      • custom classloader:根据程序自定义类加载器
    • 为什么要分层?
      • 如果自己编写了一个java.lang.String类,如果只有一个的话无法判定究竟要加载哪个。所以分层对信任级别进行划分
    • 三个特性:
      • 全盘负责:
        • 当一个类加载器加载某个class的时候,该class所依赖的和引用其他的class都由该类加载器负责载入。除非显式使用另一个类加载器
      • 父类委托(双亲委派):
        • 首先传入类的全限定名
        • 从app层依次往上找是否加载过,然后又从上往下看谁能加载,最后还没有就抛异常。
        • 可以重写loadclass打破双亲委派
        • 打破:
          • SPI,JDK提供了一套接口,定义实现类,在META-INF/services中注册实现类的相关信息,比如JDBC的DriverManager
          • OSGI:热部署、热替换
          • 如果怕打破可以重写findclass方法
      • 缓存机制:
        • 加载过的class文件在内存中(方法区)缓存

运行时数据区:

  • 常量池:
    • 静态常量池:class文件的一部分,由字面量(文本、字符串以及final修饰的)和符号引用(描述信息)组成
    • 运行时常量池:静态常量池被加载到内存后就变成了运行时常量池了,class文件内容落地到内存了
    • 字符串常量池:现在在堆中
      • 面试常问的:
        • String a ="aaaa";

          解析:最多创建一个字符串对象。先查找有没有这个,没有就创建一个,返回引用。

        • `String  a  =new  String("aaaa");`

          解析:最多会创建两个对象。常量池没有的话,就在堆中创建一个字符串对象(放字符串常量池里),再在堆中创建一个对象(独立出去),返回后面的引用。有没有都要多创建一个。

        • intern()

          • String s1 = new String("yzt");
            String s2 = s1.intern();
            System.out.println(s1 == s2); //false
            返回的是字符串常量池里的
        • 方法区:
          • 线程共享
          • 堆的一个逻辑部分,但是也要和堆区分出来
          • 存放虚拟机加载的类信息,常量、静态变量、JIT代码等等
          • 当方法区无法满足内存分配的需求时,将抛出OOM异常
          • 1.8后在系统内存中,为了避免内存泄露和OOM
        • 堆:
          • 虚拟机管理内存中最大的一块,在虚拟机启动的时候被创建,线程共享
          • 实例和数组都在堆上分配,注意java.class.class这个对象就是方法区中数据的访问入口
        • 虚拟机栈:
          • 假设现在已经初始化完成了要使用了,一个线程的运行状态就由虚拟机栈来保存,线程私有,随着线程的创建而创建。
          • 线程执行的每一个方法,就是栈中的一个栈桢,可以看作是一个方法的运行空间。
        • 程序计数器:
          • 线程切换的时候,记录正在执行的字节码指令的地址
        • 本地方法栈:
          • 如果执行Native就在本地方法栈执行
          • 如果在java方法执行的时候调用native方法,就是动态链接。

内存布局:

  • 对象内存布局:
  • 指针压缩:
    • 在64位的操作系统中,一个指针一般是八个字节,在很多情况下,并不需要使用这么多的地址空间。
    • 减少内存消耗,压缩成4字节。对于大型应用,节省空间。
    • 更好的缓存应用:能存放更多的对象
    • 提高访问速度:较小的数据结构代表着读写能够更快的完成
    • 减少垃圾回收开销:扫描和标记耗时变小
    • 无效情况:
      • 32位超过32G
      • 怎么去理解?
        • 第一种理解:对象长度一定是8的整数倍,所以只用存第一个,4G*8=32G
        • 第二种理解:当存入64位寄存器的时候,左移三位,末尾三个0是不需要的,索引寻址空间提高了8倍;
  • java采用的大端存储,便于符号判断,小端便于类型转换
  • classpointer设计:
    • 句柄池访问:对象移动的时候只需要修改一个指针,但是多一次定位的时间开销
    • 直接指针:节省了一次定位开下,在对象移动后,还需要修改引用
  • 对齐填充:
    • 8字节,举个例子,如果针对开区域存储,那么就需要读两次内存,现在读一次就可以了。也可以选择策略
      • 0:基本类型>填充类型>引用类型
      • 1:引用类型>基本类型>填充类型
      • 2:父类的引用类型和子类的引用类型放在一起,父类采用0,子类采用1,从而降低空间的开销。

运行时数据区:

  • 根据GC的悲观策略,98%的对象不能达到分代年龄
  • 内存担保机制:假设在young gc后,新生代仍然有大量的对象存活,就需要老年代进行分配担保。

什么时候Full GC?

  • 每次晋升的对象平均大小>剩余空间,基于历史水平计算 

  • 上面内存担保机制

  • 元空间内存不足

  • System.GC

  • 如何理解Minor/Major/Full GC

Minor GC:新生代
Major GC:老年代
Full GC:新生代+老年代
  • 为什么需要Survivor区?只有Eden不行吗?

如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。
这样一来,老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。
老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。
执行时间长有什么坏处?频发的Full GC消耗的时间很长,会影响大型程序的执行和响应速度。
​
可能你会说,那就对老年代的空间进行增加或者较少咯。
假如增加老年代空间,更多存活对象才能填满老年代。虽然降低Full GC频率,但是随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长。
假如减少老年代空间,虽然Full GC所需时间减少,但是老年代很快被存活对象填满,Full GC频率增加。
​
所以Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。
  • 为什么需要两个Survivor区?

最大的好处就是解决了碎片化。也就是说为什么一个Survivor区不行?第一部分中,我们知道了必须设置Survivor区。假设现在只有一个Survivor区,我们来模拟一下流程:
刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。这样继续循环下去,下一次Eden满了的时候,问题来了,此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。
永远有一个Survivor space是空的,另一个非空的Survivor space无碎片。
  • 新生代中Eden:S1:S2为什么是8:1:1?

新生代中的可用内存:复制算法用来担保的内存为9:1
可用内存中Eden:S1区为8:1
即新生代中Eden:S1:S2 = 8:1:1
现代的商业虚拟机都采用这种收集算法来回收新生代,IBM公司的专门研究表明,新生代中的对象大概98%是“朝生夕死”的
  • 堆内存中都是线程共享的区域吗?

JVM默认为每个线程在Eden上开辟一个buffer区域,用来加速对象的分配,称之为TLAB,全称:Thread Local Allocation Buffer。
对象优先会在TLAB上分配,但是TLAB空间通常会比较小,如果对象比较大,那么还是在共享区域分配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541717.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

6.4Python之字典的可变数据类型

字典是不可变数据类型,但其值都是可变数据类型。添加修改删除,都是通过改变寻址的方式做数据的变化。 例如: d1 {"a": 1, "b": 2, "c": 5} print(d1) print(id(d1)) print(d1["c"], "的ID&a…

策略者模式(代码实践C++/Java/Python)————设计模式学习笔记

文章目录 1 设计目标2 Java2.1 涉及知识点2.2 实现2.2.1 实现两个接口飞行为和叫行为2.2.2 实现Duck抽象基类(把行为接口作为类成员)2.2.3 实现接口飞行为和叫行为的具体行为2.2.4 具体实现鸭子2.2.5 模型调用 3 C(用到了大量C2.0的知识&…

笔记本台式机电脑 “睡眠和休眠”有什么区别,那个更省电

笔记本台式机电脑 Windows 系统里睡眠和休眠有什么区别,睡眠和休眠那个更省电,睡眠和休眠使用那个更好,当不用电脑时,通常有三种方式让电脑休息:关机、睡眠和休眠。关机的定义大家都懂,但睡眠和休眠就容易让…

IEDA 启动项目时出现 java: java.lang.OutOfMemoryError: GC overhead limit exceeded 异常

问题 通过Idea启动项目时,出现java: java.lang.OutOfMemoryError: GC overhead limit exceeded 内存溢出问题; 解决方案 错误是发生在编译阶段,而不是运行阶段: 【1】idea编译Java项目使用的虚拟机和idea软件自身使用的虚拟机是…

APP开发教学:开发同城O2O外卖跑腿系统源码详解

同城O2O外卖跑腿系统,满足了人们对于外卖送餐和生活服务的需求。今天,小编将为您讲解如何开发同城O2O外卖跑腿系统源码。 1.前期准备 首先,我们需要明确系统的功能需求和用户需求,包括外卖订购、配送员接单、支付功能等。其次&am…

SPP论文笔记

这篇论文讨论了在深度卷积网络中引入空间金字塔池化(SPP)层的方法,以解决传统深度卷积网络需要固定图像尺寸的限制。以下是论文各部分的总结: 1. 引言 论文指出现有的深度卷积神经网络(CNN)需要固定大小的…

计算机毕业设计Python+Flask电商商品推荐系统 商品评论情感分析 商品可视化 商品爬虫 京东爬虫 淘宝爬虫 机器学习 深度学习 人工智能 知识图谱

一、选题背景与意义 1.国内外研究现状 国外研究现状: 亚马逊(Amazon):作为全球最大的电商平台之一,亚马逊在数据挖掘和大数据方面具有丰富的经验。他们利用Spark等大数据技术,构建了一套完善的电商数据挖…

CTF之game1

拿到题目,真不错先玩几把。 对比一下不同分数的包,发现 分数不同时不同的包差距在于 score和 sign 对比sign发现 sign是由 zM **** 构成 再拿一个sign去md5解密和base64解码一下发现 sign zM base64(score) 接着便改一下包把分数改成不可能有…

React Hooks 全解: 常用 Hooks 及使用场景详解

React Hooks 是 React 16.8 版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。 React 中常用的 10 个 Hooks,包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useLayoutEffect、useImperativeHandle 和 useDebugValue。这些…

Linux的内存管理子系统

大家好,今天给大家介绍Linux的内存管理子系统,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!可进群免费领取。 Linux的内存管理子系统是Linux内核中一个非常重要且复杂的子系统&#…

wangeditor与deaftjs的停止维护,2024编辑器该如何做技术选型(一)

wangeditor暂停维护的声明: wangeditor是国内开发者开发的编辑器,用户也挺多,但是由于作者时间关系,暂停维护。 deaft的弃坑的声明: draft是Facebook开源的,但是也弃坑了,说明设计的时候存在很大…

微服务(基础篇-008-Elasticsearch分布式搜索【上】)

目录 初识elasticsearch(1) 了解ES(1.1) 倒排索引(1.2) es的一些概念(1.3) 安装es、kibana(1.4) ik分词器(1.5) ik分词器的拓展…

抽样调查方法

抽样方法是指从总体中选择一部分样本的方法。在进行统计研究时,往往无法对整个总体进行分析,而只能通过对样本的研究来推断总体的特征。因此,选择合适的抽样方法非常重要,它直接影响到研究结果的准确性和可靠性。抽样方法主要分为…

YOLOv5目标检测优化点(添加小目标头检测)

文章目录 1、前言2、如何计算参数3、YOLOv5小目标改进-13.1、结构文件3.2、结构图3.3、参数对比3.3.1、yolov5l.yaml 解析表3.3.2、 yolov5l-4P.yaml 解析表 4、YOLOv5小目标改进-24.1、结构文件4.2、结构图 5、YOLOv5小目标改进-35.1、结构文件 6、YOLOv5小目标改进-46.1、结构…

KDTree索引(K近邻搜索,半径R内近邻搜索)——PCL

K近邻搜索(K Nearest Neighbors) K近邻搜索是一种基于点数量的搜索方法,它会找到指定点附近最接近的K个邻居点。K近邻搜索中的K值是一个参数,您需要指定要搜索的邻居数量。该方法适用于需要查找固定数量邻居点的情况,…

如何将三方库集成到hap包中——通过IDE集成cmak构建方式的C/C++三方库

简介 cmake构建方式是开源三方库的主流构建方式。DevEco Studio目前以支持cmake的构建方式。本文将通过在IDE上适配cJSON三方库为例讲来解如何在IDE上集成cmake构建方式得三方库。 创建工程 在开发进行三方库适配以及napi接口开发前,我们需要创建一个三方库对应的…

给你的AppImage创建桌面快捷方式

原文链接 https://www.cnblogs.com/HGNET/p/16396589.html 运行环境:Ubuntu 22.04 LTS 1.首先准备好AppImage文件并放在一个你知道的地方 2.打开终端,在/usr/share/applications下新建APP.desktop文件(APP可以改成你的应用名称) cd /usr/s…

如何对图像进行聚类

文章来源:https://medium.com/voxel51/how-to-cluster-images-6e09bdff7361 2024 年 4 月 10 日 使用 FiftyOne、Scikit-learn和特征嵌入 在 2024 年深度学习的计算密集型环境中,集群一词最常出现在讨论 GPU 集群时--高度优化的矩阵乘法机器的大规模集…

谈谈我的软考高级考证之路(系统架构设计师篇)

系统架构设计师备考资料请移步 2023年软考高级系统架构设计师视频教程,推荐下载!获取。 备考总体策略 • 总体策略:刷视频记笔记刷真题 • 备考时间:建议报完名之后,开始备考,大致2-3个月(基础…

最优算法100例之45-不用循环乘法求1-n的和

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句。不能用循…