JVM内存结构介绍
1. 什么是JVM
我们都知道在 Windows 系统上一个软件包装包是 exe 后缀的,而这个软件包在苹果的 Mac OSX 系统上是无法安装的。类似地,Mac OSX 系统上软件安装包则是 dmg 后缀,同样无法在 Windows 系统上安装。
Java 代码为什么可以在 Windows 系统运行,也可以在 Linux 系统运行?这就是 jvm 的功劳, Java 虚拟机可以理解为一个翻译官,在 Linux 系统上将 Java 代码翻译成 Linux 机器码,在 Windows 系统上将 Java 代码翻译成 Windows 机器码,所以 Java 有了虚拟机之后,可以让 Java 代码运行在不同的系统上。
2. JVM内存结构(运行时数据区)
运行时数据区是官方说法,但很多时候这个名词并不是很形象,再加上日积月累的习惯,很多人都习惯用 JVM 内存结构这个说法
JVM 内存结构(运行时数据区)主要包括:堆、栈(虚拟机栈)、本地方法栈、方法区、程序计数器等。
线程公有:堆、方法区
线程私有:栈、本地方法栈、程序计数器
2.1 堆(公有)
堆内存被所有线程共享。堆内存用于存放由 new 创建的对象和数组。
Java堆分为年轻代(Young Generation)和老年代(Old Generation);年轻代又分为乐园(Eden)和幸存区(Survivor区);幸存区又分为 From 区(From Survivor 区)和 To 区(To Survivor 区)。
而 JVM 垃圾回收机制主要收集堆中年轻代和老年代对象所占用的内存空间。
为什么默认的虚拟机配置,Eden:from :to = 8:1:1 ?
这是经过大量统计得出的结果发现 80% 的对象存活时间都很短,于是将 Eden 区设置为年轻代的 80%,这样可以减少内存空间的浪费,提高内存空间利用率。
年轻代中的 Minor GC
1、绝大多数刚刚被创建的对象会存放在乐园(Eden)。
2、在乐园内存满时,执行第一次GC(Minor GC)之后,存活的对象被移动到其中一个幸存区(Survivor)。
3、此后,每次乐园执行GC后,存活的对象会被堆积在同一个幸存区。
4、当一个幸存区饱和,还在存活的对象会被移动到另一个幸存区。然后会清空已经饱和的那个幸存区。
5、在以上步骤中重复N次(N = MaxTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会被移动到老年代。
从上面的步骤可以发现,两个幸存者空间,必须有一个是保持空的。
需要重点记住的是,对象在刚刚被创建之后,是保存在乐园的(Eden)。那些长期存活的对象会经由幸存区(Survivor)转存到老年代(Old generation)。
也有例外出现,对于一些比较大的对象(需要分配一块比较大的连续内存空间)则直接进入到老年代(内存分配担保机制)。
注意:当年轻代满时就会触发Minor GC,这里的年轻代满指的是Eden满,Survivor满不会引发Minor GC。由于年轻代中的对象存活时间比较短,Minor GC比较频繁,GC 速度也很快。
老年代中的 Full GC
老年代空间的构成很简单,它不像新生代空间那样划分为几个区域,它只有一个区域,里面存储的对象并不像新生代一样存活时间很短。这里的对象几乎都是从Survivor 区中熬过来的,它们绝不会轻易的被回收掉。
注意:Full GC 是清理整个堆空间,包括年轻代和老年代,如果Full GC之后,堆中仍然无法存储对象,就会抛出OutOfMemoryError异常。由于老年代内存不会轻易的被回收掉,因此 Full GC 发生的次数不会有 Minor GC 那么频繁。但是老年代内存大,做一次 Full GC 的时间比 Minor GC 要更长(约10倍)。
2.2 方法区(公有)
方法区被所有线程共享。方法区用于存放静态变量、常量、类信息(版本、方法、字段等)、常量池。可以看做是将类(Class)的元数据,保存在方法区里。
Integer常量池
都知道数据类型 == 比较的是内存地址,先看个下边的例子。
public static void main(String[] args)
{
Integer i1 = 66;
Integer i2 = 66;
Integer i3 = 150;
Integer i4 = 150;
System.out.println(i1 == i2);//true
System.out.println(i3 == i4);//false
}
i1 == i2 结果为 true,i3 == i4 结果为 false。由结果得知 i1 和 i2 的内存地址是相同的,而 i3 和 i4 内存地址是不同的。
产生这样结果的原因是 Integer i1 = 66 实际上有一步装箱的操作,通过 Integer 的 valueOf 方法将 int 型的 66 装箱成 Integer。下边是 Integer 中的 valudOf 方法。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer 的 valueOf 方法很简单,它判断变量是否在 IntegerCache 的最小值(-128)和最大值(127)之间,如果在,则返回常量池中的内容,否则 new 一个 Integer 对象。
由于 66 在 -128 ~ 127 之间,所以 66 装箱时,使用的是常量池中的 66,所以 == 结果为 true。
而 150 不在范围内,在装箱时执行了 new Integer(150),所以返回的是新创建的对象,所以 == 结果为 false。
String常量池
String 是由 final 修饰的类,是不可以被继承的。通常有两种方式来创建对象。
// 1
String str = new String("abc");
// 2
String str = abc;
第一种:使用 new 创建的对象,存放在堆中,每次 new 出来的内存地址都不同。
第二种:先在常量池中找有没有 “abc”。有,则直接取常量池内存地址赋值给 str。没有,先在常量池创建“abc”,再取内存地址赋值给 str。
通过代码验证上面理论。
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("abc");
String s3 = "abc";
String s4 = "abc";
System.out.println(s1 == s2);// false
System.out.println(s3 == s4);// true
}
s1 == s2 为 false 原因:str1 和 str2 使用 new 创建对象,分别在堆上创建了不同的对象。两个引用指向堆中两个不同的对象,所以为 false。
s3 == s4 为 true 原因:首先在栈上存放变量引用 s3,然后去常量池中找是否有 abc,没有,则将 abc 存储在常量池中,然后将 s3 指向常量池的 abc。当 s4 = "abc" 时,去常量池中发现已经有 abc 了,就将 s4 引用指向常量池已有的 abc 。所以s3 == s4,指向同一个内存地址。
String 类中有一个方法 intern,可以返回池中的字符串,如下代码
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2);// false
System.out.println(s1.intern() == s2);// true
}
上边的结果可以看下 intern() 方法注释就知道结果。当调用 intern 方法时,如果常量池中已经该字符串,则返回池中的字符串;否则将此字符串添加到常量池中,并返回字符串的引用。
2.3 栈(私有)
栈是后进先出的。栈是线程私有的,他的生命周期与线程相同。每个线程都会分配一个栈的空间,一个线程会对应一个栈。
栈存储什么
栈中存储的是栈帧。每个方法在执行时都会创建一个栈帧。栈帧中存储了局部变量表、操作数栈、动态连接和方法出口等信息。每个方法从调用到运行结束的过程,就对应着一个栈帧在栈中压栈到出栈的过程。可以理解为栈帧就是线程所执行的方法。
使用递归时,会导致 StackOverflowError 错误,就是因为不断的在栈中创建栈帧,当栈帧的数量超过了栈的大小时,就会导致报错。
2.4 本地方法栈(私有)
本地方法栈是线程私有的,主要为 JVM 使用到的 Native 方法服务。Native 方法不是以 Java 语言实现的,而是以本地语言实现的(比如 C 或 C++)。
可以理解为 Native 方法是与操作系统直接交互的,比如通知垃圾收集器进行垃圾回收的代码 System.gc(),获取常量池中的字符串引用 String.intern(),都是使用 native 修饰的。
2.5 程序计数器(私有)
程序计数器是一个比较小的内存区域,可能是CPU寄存器或者操作系统内存,其主要用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。
字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。 每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。
相关文章:

JVM内存结构介绍
1. 什么是JVM 我们都知道在 Windows 系统上一个软件包装包是 exe 后缀的,而这个软件包在苹果的 Mac OSX 系统上是无法安装的。类似地,Mac OSX 系统上软件安装包则是 dmg 后缀,同样无法在 Windows 系统上安装。 Java 代码为什么可以在 Windows…...

Linux常见指令总结
ls:显示当前目录下文件列表 常用的命令行参数: -l 显示更多的文件属性 -a 显示所有的文件/目录(包括隐藏的) -d 只显示目录 ps:参数可以叠加使用。 例如:ls -la 显示所有文件…...

Day35-Linux网络管理5
Day35-Linux网络管理5 1. 网卡配置2. DNS客户端域名解析配置3. 给网卡配多个IP4. ip地址查看和设置4.1 ifconfig命令4.2 ip命令4.3 ip命令:查看和设置网络配置4.4 ip命令帮助 5. 路由5.1 路由功能分类:5.2 查看路由:5.3 路由表:5.…...

9个神奇免费AI编程助手,实现高效自动代码生成!
在AIGC技术工具快速发展的时代,对高效智能编程工具的需求和关注已达到空前的高度。本文将介绍9款免费且好用的AI编程助手工具。无论你是经验丰富的开发人员还是刚开始编程旅程的新手,这些AI代码软件都能帮助你提高项目开发的生产力、创造力和准确性&…...

Python 导入Excel三维坐标数据 生成三维曲面地形图(体) 5-3、线条平滑曲面且可通过面观察柱体变化(三)
环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fro…...

【CSP】2022–09-3 防疫大数据 100分 STL大模拟 使用map优化索引 有坑得注意
2022–09-3 防疫大数据 STL大模拟 使用map优化索引 2022–09-3 防疫大数据 STL大模拟 使用map优化索引基本思路遇到的问题(学到的东西)感悟完整代码 2022–09-3 防疫大数据 STL大模拟 使用map优化索引 这题中规中矩,不算太难也不算太简单&am…...

【Linux基础(三)】信号
学习分享 1、信号的基本概念2、查看信号列表3、常见信号名称4、signal库函数5、发送信号kill6、kill - signal (无参信号)示例6.1、kill - signal (不可靠信号)示例6.2、kill - signal (可靠信号)示例 7、信号分类7.1、信号运行原理分类7.2、信号是否携带…...

GEE图像可视化常用函数
目录 图层操作Map.addLayer()Map.centerObject() 直方图ui.Chart.image.histogram() 时间序列统计ui.Chart.image.series()ui.Chart.image.seriesByRegion() …...

c++基础语法
文章目录 前言命名空间命名空间的使用 缺省参数缺省参数的使用 函数重载函数重载的作用函数重载的使用函数重载原理 引用引用的使用引用的使用场景引用和指针 extern Cinlineauto范围fornullptr 前言 大家好我是jiantaoyab,这篇文章给大家带来的是c语言没有的一些特…...

【工作实践-07】uniapp关于单位rpx坑
问题:在浏览器页面退出登录按钮上“退出登录”字样消失,而在手机端页面正常;通过查看浏览器页面的HTML代码,发现有“退出登录”这几个字,只不过由于样式问题,这几个字被挤到看不见了。 样式代码中有一行为:…...
服务层组件
目录 连接层(Connection Pool) SQL接口(SQL Interface) 查询缓存(Caches&Buffers) Management Services&Utilities 查询分析器(Parser) 优化器(Optimizer)...

【学习笔记】VMware vSphere 6.7虚拟化入门
VMware vSphere 6.7虚拟化入门课程介绍 课程内容 1、VMware vSphere 6.7虚拟化入门课程介绍 2、ESXi6.7控制台设置 3、使用vSpkere Host client管理虚拟机 4、VMware EsXi基础操作 5、VMware Esxi存储管理 6、管理ESXi主机网络与虚拟机网络 7、安装配置vCenter Server Applia…...
如何防范企业内部安全威胁?
1 用户行为分析(UEBA) 现代化的用户行为分析产品具有多种优势功能,使企业能够有效地检测内部威胁。用户行为分析软件通过收集和分析来自各种来源的数据来分析和检测内部人员的可疑行为。这些来源包括网络日志和用户活动日志。通过检查这些数…...

内网渗透-跨域环境渗透-1
目录 smbclient工具 mimikatz工具 Kerbers协议 NTLM认证 hash传递攻击(PTH攻击) 黄金票据攻击 白银票据 MS14-068 smbclient工具 在linux里面连接远程windows共享目录,可以使用这个工具 第一种连接方式:smbclient -L 目…...

安信可IDE(AiThinker_IDE)编译ESP8266工程方法
0 工具准备 AiThinker_IDE.exe ESP8266工程源码 1 安信可IDE(AiThinker_IDE)编译ESP8266工程方法 1.1 解压ESP8266工程文件夹 我们这里使用的是NON-OS_SDK,将NON-OS_SDK中的1_UART文件夹解压到工作目录即可 我这里解压到了桌面,…...

【java数据结构】HashMap和HashSet
目录 一.认识哈希表: 1.1什么是哈希表? 1.2哈希表的表示: 1.3常见哈希函数: 二.认识HashMap和HashSet: 2.1关于Map.Entry的说明:,> 2.2Map常用方法说明: 2.3HashMap的使用案例: 2.4Set常见方法…...

基于Springboot的高校汉服租赁网站(有报告)。Javaee项目,springboot项目。
演示视频: 基于Springboot的高校汉服租赁网站(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…...

分布式解决方案
目录 1. 分布式ID1-1. 传统方案1-2. 分布式ID特点1-3. 实现方案1-4. 开源组件 2. 分布式Session2-1. 传统Session2-2. Spring-Session2-3. Token Redis2-4. JWT2-5. 拦截器统一处理Token2-6. Oauth2 3. 分布式锁3-1. redis3-2. Zookeeper 1. 分布式ID 1-1. 传统方案 时间戳U…...

力扣刷题日记——L724. 寻找数组的中心下标
1. 前言 今天是力扣刷题日记的第二天,今天依旧是一道简单题啊,慢慢来,先看看题目是什么吧。 2. 题目描述 给你一个整数数组 nums ,请计算数组的 中心下标。 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和…...

【Kotlin】类和对象
1 前言 Kotlin 是面向对象编程语言,与 Java 语言类似,都有类、对象、属性、构造函数、成员函数,都有封装、继承、多态三大特性,不同点如下。 Java 有静态(static)代码块,Kotlin 没有࿱…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...