Java-JVM 虚拟机原理调优实战

一、基础
栈帧(Stack Frame)栈空间的 基本元素,用于 方法的调用和方法的执行的数据结构

堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

String是一个特殊的包装类数据。可以用: String str = new String(“abc”);String str = “abc”;两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。比较类里面的数值是否相等时,用equals()方法;

程序计数器:指向当前线程所指向的字节码指令的(地址)行号。

本地方法栈:存放方法名有native修饰,public static native void sleep(long millis) throws InterruptedException

栈帧和方法的关系:每一个方法的执行都对应了一个栈帧入栈到出栈的过程。

什么时候分配栈帧的内存?分配多少内存?
在编译代码的时候栈帧中需要多大的局部变量表,多深的操作数据栈都已经完全确定了,因此一个栈帧需要分配多少内存,不会受程序运行期数据的影响,只取决于虚拟机的实现。

二、图解
在这里插入图片描述
2.1 栈帧详解
2.1.1 局部变量表(Local variable Table): 主要关注的栈内存,就是JVM栈中的局部变量表的部分。
局部变量表(Local variable Table)是一组储值空间,用于存放方法参数和方法的内部定义的局部变量,并且在Java编译为.class文件的时候就分配了该方法所需要的局部变量表的最大容量.

2.1.2 变量槽(Variable Slot)

是局部变量表容量的最小单位 4字节 32 位长度(4* 8) ;
blloean ,byte ,char short,int float ,【refrence】,double 和 long 8字节型需要2个Slot空间.
【reference】引用地址:一般来说虚拟机都能从直接引用或者间接引用中查找对象一下2点
在堆区存放的数据的开始索引
数据类型在方法区的数据类型

2.1.3 实例
方法执行时候,虚拟机使用局部变量表完成参数的传递,如果执行的方法是实例对象的方法,局部变量的0索引(比如x00001)就是在堆区对象实例的引用(通过this可以访问到这个地址)
其他参数按照顺序排列。

2.1.4 Slot复用
为了节省空间,Slot是可以复用的,也就是PC计数器的指令指已经超出了某个变量的作用域,(执行完毕)那么这个变量对应的Slot就会给其他变量使用,
优点:节省栈帧空间
缺点:影响垃圾回收:如果有大方法占用比较多的Slot,然后又不及时清除,或者设置为null,垃圾回收器就不能回收该内存.

2.1.5 动态连接(Dynamic Link)每个帧都包含一个指向运行时常量池中该帧所属于方法的引用,持有这个引用是为了支付方法调用过程中的动态连接。
静态解析:在类的加载的阶段的解析2.3阶段会将符号(PI)转化为直接引用(0x001),这种转化也成为静态解析。
动态连接:另外一部分,在每次运行的时候将符号转化为直接引用,这部分称之为动态连接

2.1.6 方法返回地址(父帧)1.执行方法返回的2种方法:
1.正常退出:执行到return ,就退出方法2.异常退出:发生异常且未处理,
2.无论采用 哪一种方法,在退出后都需要返回之前方法调用的位置,就是父帧

一般来说,方法正常退出时候,PC计数器的值可以作为放回的地址,栈帧中会保存这个计数器中的值,但是方法异常退出时候,返回的地址通过异常处理器表来确定的,栈帧中一般不会保存这部分的信息。

2.1.7 操作数栈:
操作数栈 和 局部变量表一致
编译为class就确定大小
Slot为基础储存单位
作用:当一个方法开始时候,方法数栈始空的,执行中,各种字节码文件指令往操作数栈中读取内容和写入内容,入栈和出栈的操作
比如算术运算就是通过操作数栈来进行的,或者调用其他方法时候是用操作数栈来传递参数的

三、 栈溢出模拟 SO(StackOverflowError)
public class Demo {
public static void main(String[] args) {
new Demo().a();
}
private void a(){
b();
}
private void b(){
a();
}
}
调试运行栈帧截图:
在这里插入图片描述

方法每次调用都会新增一个栈帧,a() 方法和 b()循环调用导致栈内存暴满。
方法的递归调用同理

四、堆Heap
新生区:
新生区是类的诞生、成长、消亡的区域,
一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
新生区又分为两部分:伊甸区(Eden Space)和幸存者区(Survivor space),所有的类都是在伊甸区被new出来的。
幸村区有两个:0区(Survivor 0 space)和1区(Survivor 1space)。
当伊甸园的空间用完时,程序又需要创建对象,Jvm的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园区中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。
那如果1区也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生MajorGC(FullGC),进行养老区的内存清理。若养老区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError“。

如果出现java.lang.OutOfMemoryError:Java heap space异常,说明Java虚拟机的对内存不够。原因有二:  
(1)Java虚拟机的堆内存设置不够,可以通过参数-Xms、Xmx来调整。  
(2)代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)

Java堆从GC的角度还可以细分为:新生代(Eden区、From Survivor区和To Survivor区)和老年代。
在这里插入图片描述

MinorGC的过程(复制->清空->互换),其中,Eden:From:To = 8:1:1
1:eden、SurvivorFrom复制到survivorTo,年龄+1  首先,把Eden和SurvivorFrom区域中存活的对象复制到SurvivorTo区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果SurvivorTo不够位置了就放到老年区) 
2:清空eden、SurvivorFrom  然后,清空Eden和SurvivorFrom中的对象  
3:SurvivorTo和SurvivorFrom互换  最后,SurvivorTo和SurvivorFrom互换,原SurvivorTo成为下一次GC时SurvivorFrom区

Java1.8之后将最初的永久代取消了,由元空间取代。  
在Java8中,永久代已经被移除了。被一个称为元空间的区域所取代。元空间的本质和永久代类似。  
元空间与永久代之间最大的区别在于:  
元空间并不在虚拟机中而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据当如native memeory,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不在由MaxPermSize控制,而由系统的实际可用空间来控制。
在这里插入图片描述

通过下面实例可以观察Heap 中新生区[eden->surviorFrom0->surviorFrom1]->老年代区[old] 内存变化到内存报错
报错:Exception in thread “main” java.lang.OutOfMemoryError: Java heap space

public class HeapOom {

private byte[] b = new byte[1024];

public static void main(String[] args) throws InterruptedException {
    ArrayList<HeapOom> list = new ArrayList<>();
    while(true){
        list.add(new HeapOom());
        Thread.sleep(10);
    }
}

}
堆内存空间调整参数

参数名称 描述
-Xms 设置初始分配大小,默认为物理内存的1/64
-Xmx 最大分配内存,默认为物理内存的1/4
-XX:+PrintGCDetails 输出详细的GC处理日志
-XX:+PrintGCTimeStamps 输出GC的时间戳信息
-XX:+PrintGCDateStamps 输出GC的时间戳信息(以日期的形式,如2019-09-15T16:24:24.155+0800)
-XX:+PrintHeapAtGC 在GC进行处理的前后打印堆内存信息
-Xloggc:保存路径 设置日志信息保存文件

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

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

相关文章

Linux 管道

目录 一、认识管道 二、匿名管道 pipe函数 用法&#xff1a; pipefd&#xff1a; 匿名管道通信&#xff1a; 三、命名管道 概念&#xff1a; 创建&#xff1a; 特性&#xff1a; 用途&#xff1a; 四、命名管道和匿名管道的区别 命名&#xff1a; 持久性&#xff1a;…

汽车电子拓扑架构的演进过程

汽车电子拓扑架构的演进过程 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师 (Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再挣扎,出门靠…

系统渐渐沦为“屎山”,这就是真相!

分享是最有效的学习方式。 博客&#xff1a;https://blog.ktdaddy.com/ 背景 小猫维护现有的系统也有一段时间了&#xff0c;踩坑也不少&#xff0c;事故不少。感兴趣的小伙伴可以了解一下&#xff0c;往期的小猫踩坑记合集。 这天&#xff0c;小猫找到了商城系统的第一任开发…

Springboot-软件授权License

无意中看到了一个简单方便的授权方式&#xff0c;只需几步就可集成到boot项目中。 先上地址&#xff1a;smart-license: 保护个人与企业的软件作品权益&#xff0c;降低盗版造成的损失。PS&#xff1a;因个人精力有限&#xff0c;不再提供该项目的咨询答疑服务。 Smart-licen…

Smart Light Random Memory Sprays Retinex 传统图像增强 SLRMSR

文章目录 前言1、Smart Light Random Memory Sprays Retinex概况2、Smart Light Random Memory Sprays Retinex的实现2.1、SLRMSR算法的伪代码2.2、初始化记忆喷雾&#xff08;CreateInitialMemorySpray&#xff09;2.3、更新记忆喷雾 (UpdateMemorySpray)2.4、计算颜色校正因子…

二十几岁的我们:在旷野中找寻自我

二十几岁&#xff0c;这是一个充满变数、充满机遇和挑战的年纪。它如同一片辽阔的旷野&#xff0c;每个人都在其中寻找自己的方向&#xff0c;摸索着自己的道路。这是一个既令人兴奋又令人迷茫的年纪&#xff0c;我们穿着不同的鞋子&#xff0c;注定要走不同的路。 在这个年纪里…

onnx 格式模型可视化工具

onnx 格式模型可视化工具 0. 引言1. 可视化工具2. 安装 Netron: Viewer for ONNX models 0. 引言 ONNX 是一种开放格式&#xff0c;用于表示机器学习模型。ONNX 定义了一组通用运算符&#xff08;机器学习和深度学习模型的构建基块&#xff09;和通用文件格式&#xff0c;使 A…

Unity引擎是否被过度吹嘘?

提到Unity&#xff0c;人们基本上持有以下几种观点&#xff1a; A. 很多人十分欣赏Unity在跨平台兼容性和大规模开放世界场景方面的出色表现。其渲染、环境特效以及AI系统为设计多样化沙盒游戏提供了强大支持。这使得Unity非常适合开发具有多种游戏玩法和互动系统的作品。 B. 一…

Java有哪些常用的集合?

1、典型回答 在 Java 中&#xff0c;常用的集合有以下几个&#xff1a; 列表(List)&#xff1a;有序集合&#xff0c;可以包含重复元素。常见实现类有 ArrayList、LinkedList、 Vector 等集合(Set)&#xff1a;无序集合&#xff0c;不允许包含重复元素。常见实现类有 HashSet、…

【复现】【免费】基于多时间尺度滚动优化的多能源微网双层调度模型

目录 主要内容 部分代码 结果一览 1.原文结果 2.程序运行结果 下载链接 主要内容 该模型参考《Collaborative Autonomous Optimization of Interconnected Multi-Energy Systems with Two-Stage Transactive Control Framework》&#xff0c;主要解决的是一个…

深入了解JVM底层原理

一、JVM内存结构 1、方法区&#xff1a;存储编译后的类、常量等&#xff08;.class字节码文件&#xff09; 2、堆内存&#xff1a;存储对象 3、程序计数器&#xff1a;存储当前执行的指令地址&#xff08;计算机处理器&#xff08;CPU&#xff09;正在执行的下一条指令在内存…

win修改图标自定义QQ桌面图标

当安装了TIM后&#xff0c;想把图标改成QQ 图标见顶部&#xff0c;或通过网盘下载 提取码&#xff1a;9Ayc 操作步骤&#xff1a; 1.桌面右键图标&#xff0c;点击属性 2.选择快捷方式-更改图标 3.浏览选择下载的ico图标即可

Python中的迭代器与生成器提高性能的秘密武器【第143篇—迭代器与生成器】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的迭代器与生成器&#xff1a;提高性能的秘密武器 在Python编程中&#xff0c;迭代…

17双体系Java学习之数组的长度

数组的长度 //获取数组长度 arrays.lengthfor (int i 0; i <nums.length; i) {sum sum nums[i];}System.out.println("总和为&#xff1b;"sum);

心灵治愈交流平台|基于springboot框架+ Mysql+Java+B/S结构的心灵治愈交流平台设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 用户功能模块 心理咨询师功能 系统功能设计 数据库…

Linux下使用ntpdate进行时间同步

1.简介 ntpdate是Linux下用于从NTP服务器同步时间的命令行工具。 2.安装 大多数Linux发行版已预装ntpdate。未安装的可使用以下命令&#xff1a; # Ubuntu/Debian sudo apt-get install ntpdate # CentOS/Fedora/RHEL sudo yum install ntpdate 3.手工同步网络时间 执行以下命…

操作系统原理与实验——实验七固定分区的分配与回收

实验指南 运行环境&#xff1a; Dev c 算法思想&#xff1a; 本实验是模拟存储管理方式中的固定分区分配与回收算法&#xff0c;系统在作业装入前预分将整个用户区划分为若干个大小确定的分区&#xff0c;然后根据待装入作业的名称和大小到分区列表中查找满足要求的空闲分区&am…

鸿蒙Next-TextInput制作简易登录页面

Entry Component struct EventCase {State username: string State password: string build() {Row() {Column({ space: 30 }) {TextInput({ placeholder: 请输入用户名, text: $$this.username }).height(40)TextInput({ placeholder: 请输入密码, text: $$this.password })…

【网络原理】TCP协议详细解析

文章目录 &#x1f332;TCP协议的概念&#x1f338;TCP协议段格式&#x1f338;TCP的特性 &#x1f333;TCP原理详解&#x1f338;确认应答机制&#xff08;安全机制&#xff09;&#x1f338;超时重传机制&#xff08;安全机制&#xff09;&#x1f338;连接管理&#xff08;安…

电脑缺少dll文件一键修复的方法,如何快速修复dll文件

如果你遇到了电脑缺少dll文件&#xff0c;那么也不要慌&#xff0c;要解决也是比较简单的&#xff0c;下面我们一起来了解一下电脑缺少dll文件一键修复的方法&#xff0c;教教大家快速修复。 一.什么是dll文件 DLL 文件全称为“Dynamic Link Library”文件&#xff0c;翻译为中…