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 没有࿱…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
