【JVM】剖析字符串与数组的底层实现(一)

剖析字符串与数组的底层实现

字符数组的存储方式

在这里插入图片描述
在这里插入图片描述

JVM有三种模型:

  • 1.Oop模型:Java对象对应的C++对象
  • 2.Klass模型:Java类在JVM对应的C++对象
  • 3.handle模型

字符串常量池

在这里插入图片描述

即String Pool,但是JVM中对应的类是StringTable,底层实现是一个hashtable,如代码所示

JVM有三种常量池:

  • 1.静态常量池(通过字节码方式查到地引用都是间接引用)
  • 2.运行时常量池
  • 3.字符串常量池->StringTable
    key生成规则->String内容+长度生成哈希值,然后将hash值取模转为key
    value生成规则->将Java地String类的实例InstanceOopDesc封装成HashtableEntry

字符串常量池位置

JDK1.6及之前:有永久代,运行时常量池在永久代,运行时常量池包含字符串常量池,Perm区域只有4m,一旦常量池大量使用intern很容易发生永久代的OOM
JDK1.7:有永久代,但已经逐步"去永久代",字符串常量池从永久代里的运行时常量池分离到堆里
JDK1.8及之后,无永久代,运行时常量池在元空间,字符串常量池依然在堆里

字符串常量池的设计思想:

  • 1.字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序地性能
  • 2.JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
    2.1 为字符串开辟一个字符串常量池,类似于缓存区
    2.2 创建字符串常量时,首先查询字符串常量池是否存在该字符串
    2.3 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

字符串常量池设计原理

在这里插入图片描述

字符串常量池底层时HotSpot的C++实现的。底层类似一个Hashtable,保存的本质上是字符串对象的引用,来看一道比较常见的案例,图中的代码创建了多少个String对象
// JDK6:false 创建了6个对象
// JDK7及以上:true 创建了5个对象

为什么输出会有这些变化呢?主要还是字符串从永久代中脱离、移入堆区的原因,intern()方法也相应发生了变化
同时也解释了JDK1.6中字符串溢出会抛出OutOfMemoryError:PermGen Space.而在JDK1.7及以上版本会抛出OutOfMemoryError:Java heap space

在这里插入图片描述

在JDK1.6中,调用intern()首先会在字符串池中寻找equals相等的字符串,加入字符串存在就返回该字符串在字符串池中的引用,假如字符串不存在,虚拟机会重新在永久代上创建一个实例,将StringTable的一个表项指向这个新创建的实例
在这里插入图片描述

在JDK1.7(及以上版本)中,由于字符串池不在永久代了,intern()做了一些修改,更方便地利用堆中的对象。字符串存在时和JDK1.6一样,但是字符串不存在时不再需要重新创建实例,可以直接指向堆上的实例

我们再来看一个例子
在这里插入图片描述
JDK1.7以上:false true
JDK1.6: false false

在这里插入图片描述

jdk1.6代码图
在JDK1.6中上述的所有打印都是false,因为jdk6的常量池是放在Perm区中的,Perm区和正常的Java Heap区域是完全分开的。如果是使用引号声明的字符串都是会直接在字符串常量池中生成,而new出来的String对象是放在Java Heap区域。所以拿一个Java Heap区域的对象地址和字符串常量池的对象地址进行比较比较肯定是不相同的,即使调用String.inern方法也是没有关系的

在这里插入图片描述

jdk1.7代码图
这里要明确一点的是,在Jdk6以及以前的版本中,字符串的常量池是放在堆的Perm区的,Perm区是一个类静态的区域,主要存储一些加载类的信息,常量池,方法片段等内容,默认大小只有4m,一旦常量池中大量使用intern是会直接产生java.lang.OutOfMemoryError:PermGen Space错误的。Perm区域太小是一个主要原因,当然在1.8中已经直接取消了Perm区域,而新建立了一个元区域。应该是jdk开发者认为Perm区域已经不适合现在Java的发展了。
正是因为字符串常量池移动到Java Heap区域后,再看下面解释。

  • 1.先看s3和s4字符串,String s3 = new String(“1”) + new String(“1”);这句代码中现在生成了两个对象,一个是字符串常量池中的"1",另一个是Java Heap中的s3引用指向的对象。中间还有2个匿名的new String(“1”),不去讨论他们,此时s3引用对象内容是"11",但此时常量池中是没有"11"对象的
  • 2.接下来,s3.intern(); 这一句代码,是将s3中的"11"字符串放入String常量池中,因为此时常量池中不存在"11"字符串,因此常规做法是跟jdk6图中所示的一样,再常量池中生成一个"11"的对象,关键点是jdk7中常量池不在Perm区域了,这块做了调整。常量池中不需要再存储一份对象了,可以直接存储堆中的引用。这份引用指向s3引用的对象。也就是说引用地址是相同的
  • 3.最后String s4 = “11”;这句代码中"11"是显式声明的,因此会直接区常量池中创建,创建的时候发现已经有这个对象了,此时也就是指向s3引用对象的一个引用。所以s4引用就指向和s3一样了,因此最后的比较s3 == s4 是true
  • 4.再看s和s2对象,String s = new String(“1”);第一句代码,生成了2个对象。常量池中的"1"和Java Heap中的字符串对象 s.intern()这一句是s对象区常量池中寻找后发现"1"已经再常量池里了
  • 5.接下来String s2 = “1”;这句代码是生成一个s2的引用指向常量池中的"1"对象。结果就是s和s2引用地址明显不同

例子二
在这里插入图片描述

JDK1.7以上:false false
JDK1.6 false false

在这里插入图片描述

  • 1.代码一和代码二的改变就是s3.intern的顺序是放在了String s4 = "11"后了,这样,首先执行String s4 = “11”;声明s4的时候常量池中是不存在"11"对象的。执行完毕后"11"对象是s4声明产生的对象。然后再执行s3.intern时,发现常量池中"11"对象已经存在了,因此s3和s4的引用时不同的
  • 2.s和s2代码中,s.intern()这一句往后放也不会有什么影响了,因为对象池中执行第一句代码String s = new String(“1”);的时候已经生成"1"对象的了,下边的s2声明都是直接从常量池中取地址引用的,s和s2的引用地址是不会相等的

key的生成方式

在这里插入图片描述

1.通过String的内容 + 长度生成hash值
2.将hash值转为key
在这里插入图片描述

hash生成方式

在这里插入图片描述

通过hash计算索引

value的生成方式

将Java的String类的实例InstanceOopDesc封装成HashtableEntry
在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三级_网络技术_42_综合题(命令)

一、 如图所示,某园区网用10Gbps的POS技术与intemet相连,POS接囗的帧格式是SDH。在R3上配置一个oopback接口,"P地址为10.2.15.1,路由协议的选择方案是,园区网内部采用OSPF动态路由协议,园区网与Inter…

如何使用ssm实现基于面向对象的学生事务处理系统分析与设计

TOC ssm138基于面向对象的学生事务处理系统分析与设计jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大,随着当前时代的信息化,科学化发展,让社会各行业领域都争相使用新的信息技术,对行业内的各种相关数据进行科学化…

go中 panicrecoverdefer机制

go的defer机制-CSDN博客 常见panic场景 数组或切片越界,例如 s : make([]int, 3); fmt.Println(s[5]) 会引发 panic: runtime error: index out of range空指针调用,例如 var p *Person; fmt.Println(p.Name) 会引发 panic: runtime error: invalid m…

AJAX(4)——XMLHttpRequest

XMLHttpRequest 定义:XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用于操作的情况下,更新页面的局部内容。XMLHttpRequest在AJAX编程中被大量使用 关系…

MATLAB 手动实现点云投影滤波器 (76)

点云投影到邻近的精确拟合平面,减少噪声点,此为投影滤波器 MATLAB 手动实现点云投影滤波器(76) 一、投影滤波器简介二、实现步骤二、算法实现1.代码2.效果这里用到的投影方法和平面拟合方法以及生成平面方法都在以往文章有所实现,有兴趣可参考: MATLAB点云处理总目录 一…

C++动态规划及九种背包问题

目录 目录 一,动态规划 一),动态规划的定义 二),动态规划其他的相关概念(也是使用条件) 1,重叠子问题 2, 最优子结构 3,无后效性 三)&…

dompdf导出pdf中文乱码显示问号?、换行问题、设置图片大小

环境:PHP 8.0 框架:ThinkPHP 8 软件包:phpoffice/phpword 、dompdf/dompdf 看了很多教程(包括GitHub的issue、stackoverflow)都没有解决、最终找到解决问题的根本! 背景:用Word模板做转PDF…

【JavaEE初阶】IP协议

目录 📕引言 🌴IP协议的概念 🌳IP数据报 🚩IPv4协议头格式 🚩IPv6的诞生 🏀拓展 🎄IP地址 🚩IP地址的格式: 🚩IP地址的分类 🏀网段划分…

【第57课】SSRF服务端请求Gopher伪协议无回显利用黑白盒挖掘业务功能点

免责声明 本文发布的工具和脚本,仅用作测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。 如果任何单位或个人认为该项目的脚本可能涉嫌侵犯其权利&#xff0…

Unity动画模块 之 Animator中一些常见参数

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 我发现我忘了写Animator了,正好有些不常用的参数还没怎么认识,笔记来源于唐老狮 1.状态窗口参数 2.连线参数…

如何使用ssm实现学生公寓管理系统的设计与实现

TOC ssm106学生公寓管理系统的设计与实现jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大,随着当前时代的信息化,科学化发展,让社会各行业领域都争相使用新的信息技术,对行业内的各种相关数据进行科学化,…

Qt第十八章 XML和Json格式解析

文章目录 JSON格式解析Json生成案例 XML简介与HTML的区别格式XML解析流的方式DOM XML生成 JSON与XML的区别比较 JSON 格式 JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名 六个构造字符 开始和结束数组:[ ]开始和结束对象&#x…

简易STL实现 | Vector的实现

1、内存管理 1、std::vector 维护了两个重要的状态信息:容量(capacity:当前 vector 分配的内存空间大小)和大小(size: vector 当前包含的元素数量) 2、当容量不足以容纳新元素时,s…

SSH 远程登录报错:kex_exchange_identification: Connection closed.....

一 问题起因 在公司,使用ssh登录远程服务器。有一天,mac终端提示:`kex_exchange_identification: Connection closed by remote host Connection closed by UNKNOWN port 65535`。 不知道为啥会出现这样的情形,最近这段时间登录都是正常的,不知道哪里抽风了,就提示这个。…

巴恩斯利蕨数学公式及源码实现——JavaScript版

为什么要写这篇文章 本篇接《张侦毅:巴恩斯利蕨数学公式及源码实现》。之前文章中源码的编程语言用的是Java,JDK的版本为8,现在我的JDK版本已经升级到22了,在新版本JDK中,原来的JApplet方法已经被废弃,不能…

鸿蒙实现在图片上进行标注

一.实现思路 现在需求是:后端会返回在这张图片上的相对位置,然后前端这边需要在图片上进行标注,就是画个框框圈起来,返回的数据里包括当前框的x,y坐标和图片大小,大体思路就是使用canvas绘制,使用鸿蒙的st…

vue-element-admin解决三级目录的KeepAlive缓存问题(详情版)

vue-element-admin解决三级目录的KeepAlive缓存问题(详情版) 本文章将从问题出现的角度看看KeepAlive的缓存问题,然后提出两种解决方法。本文章比较详细,如果只是看怎么解决,代码怎么改,请前往配置版。 一…

零工市场小程序应该有什么功能?

数字经济现如今正飞速发展,零工市场小程序在连接雇主与自由职业者方面发挥着越来越重要的作用。一个高效的零工市场小程序不仅需要具备基础的信息发布与匹配功能,还应该涵盖交易管理、安全保障以及个性化服务等多个方面。 那么,零工市场小程…

Ubuntu22.04下安装LDAP

目录 1 简单说明2 安装配置2.1 安装1、安装前准备2、安装 OpenLADP3、配置OpenLDAP4、设置基本组5、添加新组5、添加 OpenLDAP 用户 2.2 安装 LDAP 帐户管理器1、安装2、配置 LDAP 帐户管理器 3 简单使用3.1 创建一个组3.2 创建一个用户 总结 1 简单说明 之前写过在Centos下的…

nginx和tomcat负载均衡,动静分离

文章目录 一,tomcat1.tomca用途2.tomcat重要目录 二,nginx1.Nginx应用2.nginx作用3.nginx的正向代理和反向代理3.1正向代理3.2反向代理(单级)3.3反向代理(多级) 4.nginx负载均衡4.1Nginx支持的常见的分流算法1. 轮询(Round Robin):2.最少连接数(LeastCon…