JVM——常量池

news2024/11/23 12:22:24

目录

    • 一、常量池
    • 二、运行时常量池
    • 三、intern方法 1.8
    • 四、intern方法 1.6
    • 五、StringTable 垃圾回收
    • 六、StringTable调优

通过解决以下问题可以更深入了解字符串创建过程中的原理
在这里插入图片描述

一、常量池

二进制字节码的组成:类的基本信息、常量池、类的方法定义(包含了虚拟机指令)

通过反编译来查看类的信息

● 获得对应类的.class文件

  ① 在JDK对应的bin目录下运行cmd,也可以在IDEA控制台输入

  ② 输入 javac 对应类的绝对路径
   (F:\JAVA\JDK8.0\bin>javac F:\Thread_study\src\com\nyima\JVM\day01\Main.java)
   输入完成后,对应的目录下就会出现类的.class文件
● 在控制台输入 javap -v 类的绝对路径

  javap -v F:\Thread_study\src\com\nyima\JVM\day01\Main.class
  然后能在控制台看到反编译以后类的信息了

类的基本信息
在这里插入图片描述
常量池
在这里插入图片描述
在这里插入图片描述
虚拟机中执行编译的方法(框内的是真正编译执行的内容,#号的内容需要在常量池中查找)
在这里插入图片描述

二、运行时常量池

常量池
就是一张表(如上图中的constant pool),虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量信息

运行时常量池
常量池是.class文件中的,当该* 类被加载以后,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址 **

常量池与串池的关系

串池StringTable
特征

● 常量池中的字符串仅是符号,只有在被用到时才会转化为对象
● 利用串池的机制,来避免重复创建字符串对象
● 字符串变量拼接的原理是StringBuilder
● 字符串常量拼接的原理是编译器优化
● 可以使用intern方法,主动将串池中还没有的字符串对象放入串池中
注意:无论是串池还是堆里面的字符串,都是对象

用来放字符串对象且里面的元素不重复

public class StringTableStudy {
	public static void main(String[] args) {
		String a = "a"; 
		String b = "b";
		String ab = "ab";
	}
}

常量池中的信息,都会被加载到运行时常量池中,但这是a b ab 仅是常量池中的符号,还没有成为java字符串

0: ldc           #2                  // String a
2: astore_1
3: ldc           #3                  // String b
5: astore_2
6: ldc           #4                  // String ab
8: astore_3
9: return

当执行到 ldc #2 时,会把符号 a 变为 “a” 字符串对象,并放入串池中(hashtable结构 不可扩容)

当执行到 ldc #3 时,会把符号 b 变为 “b” 字符串对象,并放入串池中

当执行到 ldc #4 时,会把符号 ab 变为 “ab” 字符串对象,并放入串池中

最终StringTable [“a”, “b”, “ab”]

注意:字符串对象的创建都是懒惰的,只有当运行到那一行字符串且在串池中不存在的时候(如 ldc #2)时,该字符串才会被创建并放入串池中。

使用拼接字符串变量对象创建字符串的过程

public class StringTableStudy {
	public static void main(String[] args) {
		String a = "a";
		String b = "b";
		String ab = "ab";
		//拼接字符串对象来创建新的字符串
		String ab2 = a+b; 
	}
}

反编译后的结果

	 Code:
      stack=2, locals=5, args_size=1
         0: ldc           #2                  // String a
         2: astore_1
         3: ldc           #3                  // String b
         5: astore_2
         6: ldc           #4                  // String ab
         8: astore_3
         9: new           #5                  // class java/lang/StringBuilder
        12: dup
        13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
        16: aload_1
        17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String
;)Ljava/lang/StringBuilder;
        20: aload_2
        21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String
;)Ljava/lang/StringBuilder;
        24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/Str
ing;
        27: astore        4
        29: return

通过拼接的方式来创建字符串的过程是:StringBuilder().append(“a”).append(“b”).toString()

最后的toString方法的返回值是一个新的字符串,但字符串的和拼接的字符串一致,但是两个不同的字符串,一个存在于串池之中,一个存在于堆内存之中

String ab = "ab";
String ab2 = a+b;
//结果为false,因为ab是存在于串池之中,ab2是由StringBuffer的toString方法所返回的一个对象,存在于堆内存之中
System.out.println(ab == ab2);

使用拼接字符串常量对象的方法创建字符串

public class StringTableStudy {
	public static void main(String[] args) {
		String a = "a";
		String b = "b";
		String ab = "ab";
		String ab2 = a+b;
		//使用拼接字符串的方法创建字符串
		String ab3 = "a" + "b";
	}
}

反编译后的结果

 	  Code:
      stack=2, locals=6, args_size=1
         0: ldc           #2                  // String a
         2: astore_1
         3: ldc           #3                  // String b
         5: astore_2
         6: ldc           #4                  // String ab
         8: astore_3
         9: new           #5                  // class java/lang/StringBuilder
        12: dup
        13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
        16: aload_1
        17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String
;)Ljava/lang/StringBuilder;
        20: aload_2
        21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String
;)Ljava/lang/StringBuilder;
        24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/Str
ing;
        27: astore        4
        //ab3初始化时直接从串池中获取字符串
        29: ldc           #4                  // String ab
        31: astore        5
        33: return

● 使用拼接字符串常量的方法来创建新的字符串时,因为内容是常量,javac在编译期会进行优化,结果已在编译期确定为ab,而创建ab的时候已经在串池中放入了“ab”,所以ab3直接从串池中获取值,所以进行的操作和 ab = “ab” 一致。
● 使用拼接字符串变量的方法来创建新的字符串时,因为内容是变量,只能在运行期确定它的值,所以需要使用StringBuilder来创建

三、intern方法 1.8

调用字符串对象的intern方法,会将该字符串对象尝试放入到串池中

● 如果串池中没有该字符串对象,则放入成功
● 如果有该字符串对象,则放入失败
无论放入是否成功,都会返回串池中的字符串对象

注意:此时如果调用intern方法成功,堆内存与串池中的字符串对象是同一个对象;如果失败,则不是同一个对象

例1

public class Main {
	public static void main(String[] args) {
		//"a" "b" 被放入串池中,str则存在于堆内存之中
		String str = new String("a") + new String("b");
		//调用str的intern方法,这时串池中没有"ab",则会将该字符串对象放入到串池中,此时堆内存与串池中的"ab"是同一个对象
		String st2 = str.intern();
		//给str3赋值,因为此时串池中已有"ab",则直接将串池中的内容返回
		String str3 = "ab";
		//因为堆内存与串池中的"ab"是同一个对象,所以以下两条语句打印的都为true
		System.out.println(str == st2);
		System.out.println(str == str3);
	}
}

例2

public class Main {
	public static void main(String[] args) {
        //此处创建字符串对象"ab",因为串池中还没有"ab",所以将其放入串池中
		String str3 = "ab";
        //"a" "b" 被放入串池中,str则存在于堆内存之中
		String str = new String("a") + new String("b");
        //此时因为在创建str3时,"ab"已存在与串池中,所以放入失败,但是会返回串池中的"ab"
		String str2 = str.intern();
        //false
		System.out.println(str == str2);
        //false
		System.out.println(str == str3);
        //true
		System.out.println(str2 == str3);
	}
}

四、intern方法 1.6

调用字符串对象的intern方法,会将该字符串对象尝试放入到串池中

如果串池中没有该字符串对象,会将该字符串对象复制一份,再放入到串池中
如果有该字符串对象,则放入失败
无论放入是否成功,都会返回串池中的字符串对象

注意:此时无论调用intern方法成功与否,串池中的字符串对象和堆内存中的字符串对象都不是同一个对象

五、StringTable 垃圾回收

StringTable在内存紧张时,会发生垃圾回收

六、StringTable调优

● 因为StringTable是由HashTable实现的,所以可以适当增加HashTable桶的个数,来减少字符串放入串池所需要的时间

-XX:StringTableSize=xxxx

●考虑是否需要将字符串对象入池,可以通过intern方法减少重复入池

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

集合的框架体系和Collection接口

1.集合的理解和好处 前面我们保存多个数据使用的是数组&#xff0c;那么数组有不足的地方&#xff0c;我们分析一下 1.1数组 1)长度开始时必须指定&#xff0c;而且一旦指定&#xff0c;不能更改 2)保存的必须为同一类型的元素 3)使用数组进行增加/删除元素的示例代码-比较麻烦…

调试3D渲染和3D可视化的五个好处

建筑和建筑环境是我们日常生活中不可避免的一部分&#xff0c;直接影响我们和我们的福祉。它可以是我们的家、办公室、附近的教堂或城市的商业综合体;所有这一切的设计和规划都是建筑。然而&#xff0c;具有讽刺意味的是&#xff0c;建筑的交流往往并不具有包容性。例如&#x…

玩以太坊链上项目的必备技能(函数及其可见性和状态可变性-Solidity之旅十三)

状态变量可见性 在这之前的文章里&#xff0c;给出的例子中&#xff0c;声明的状态变量都修饰为public&#xff0c;因为我们将状态变量声明为public后&#xff0c;Solidity 编译器自动会为我们生成一个与状态变量同名的、且函数可见性为public的函数&#xff01; 在 Solidity…

ASP.NET Core 3.1系列(19)——EFCore中的添加实体操作

1、前言 前面介绍了EFCore中关于查询和执行原生SQL的操作&#xff0c;这篇博客就来介绍一下EFCore中添加实体的相关操作。关于添加实体&#xff0c;EFCore提供了多种方法供开发者使用。但EFCore中针对实体的一系列操作最终都会被转换成SQL&#xff0c;因此这些方法之间也存在着…

设计模式之模版方法模式

Template method design pattern 模版方法模式的概念、模版方法模式的结构、模版方法模式的优缺点、模版方法模式的使用场景、模版方法模式的实现示例、模版方法模式的源码分析 1、模版方法模式的概念 模版方法模式&#xff0c;即定义一个算法骨架&#xff0c;而将一些步骤延迟…

ARM——指令集仿真环境搭建

目录 一、ARM指令集仿真环境搭建 1.1指令和指令集 指令 指令集 1.2汇编的本质 汇编 C语言 1.3为什么学习汇编 1.4仿真 硬件仿真 软件仿真 1.5Keil 1.6环境搭建 1.7汇编工程创建 二、汇编 2.1汇编中的符号 2.2ARM指令集 2.3简单的ARM程序 一、ARM指令集仿真环境搭…

Cyanine5 NHS ester |分子量:616.19|分子式:C36H42ClN3O4

Cyanine5 NHS ester |分子量&#xff1a;616.19|分子式&#xff1a;C36H42ClN3O4 外观&#xff1a;暗蓝色粉末 分子量&#xff1a;616.19 分子式&#xff1a;C36H42ClN3O4 溶解性&#xff1a;易溶于有机溶剂&#xff08;DMF,DMSO和氯化物&#xff09;&#xff0c;难溶于水 …

Mob社会化分享集成ShareSDK

如何在项目已经集成 SMSSDK 的情况下集成 ShareSDk 到项目中&#xff0c;需要使用创建 module 的方式引入 ShareSDk&#xff0c;主要内容如下&#xff1a; 1.下载ShareSDK 2.引入 ShareSDK 3.创建 MainLibs Module 4.创建 OneKeyShare Module 5.在项目中引入 Module 6.配…

Unity Addressables资源管理 主设置面板

Addressables资源管理总目录 0.主设置菜单位置 位置1 位置2 1.Profiles 路径配置选项 这个是全局路径配置的选择 可以点击 Manager Profiles 打开路径配置面板 打包路径设置 2.Diagnostics 诊断设置 Send Profiler Events 打开这个选项&#xff0c;才能在Event Viewer窗口…

记录java枚举类在数据库、前后端交互时的序列化方式

实体类枚举属性持久化到数据库 1.EnumValue 2.配置 mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler 或 mybatis-plus:typeEnumsPackage: xxx 实体类中枚举属性自动转为EnumValue标记的属性值 从数据…

C++数学与算法系列之排列和组合

1. 前言 本文将聊聊排列和组合&#xff0c;排列组合是组合学最基本的概念&#xff0c;在程序运用中也至关重要。 排列问题&#xff1a;指从给定个数的元素中取出指定个数的元素进行排序。 组合问题&#xff1a;指从给定个数的元素中仅仅取出指定个数的元素&#xff0c;不排序…

Docker镜像

镜像是一种轻量级、可执行的独立软件包&#xff0c;它包含运行某个软件所需的所有内容&#xff0c;我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等)&#xff0c;这个打包好的运行环境就是image镜像文件。 只有通过这…

【设计模式】工厂方法模式Factory(Java)

文章目录1. 定义2. 类图3. Java实现案例3.1 抽象类&#xff1a;Pizza和PizzaStore3.2 具体披萨&#xff1a;北京两种上海两种共四种3.3 具体披萨店&#xff1a;北京店和上海店3.4 测试主方法1. 定义 工厂方法模式定义了一个创建对象的接口&#xff0c;但由子类决定要实例化的类…

基于JAVA的XX公司固定资产管理系统的设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 本课题研究对象是中小企业财务管理系统&#xff0c;设计采用自己开发实践和所学知 识&#xff0c;系统部分主要分为以下…

汽车主机厂Adams/Car悬架动力学开发最全攻略

​​​​​​​一、写在前面 实际经历告诉我们&#xff0c;当我们接触一个新事物或学习一项新的技能时&#xff0c;入门往往是最为困难的&#xff0c;迷茫、彷徨、无助…… 正是基于同样的经历&#xff0c;在掌握Adams/Car软件的应用后&#xff0c;作者即开始构思如何将自己的…

论文投稿指南——中文核心期刊推荐(电工技术)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

linux后台自定义后台服务service(已filebeat举例)

文章目录一、配置攥写1&#xff09;安装filebeat和配置相关修改2&#xff09;常用命令二、启动顺序1&#xff09;命令循序2&#xff09;systemctl添加自定义系统服务&#xff08;服务填写指南&#xff09;3&#xff09;linux的systemctl命令详解及使用教程三、遇到的坑点和报错…

One-Hot 独热编码

1. 什么是独热编码 独热编码&#xff0c;又称一位有效编码。采用N位状态寄存器来对N个状态进行编码&#xff0c;直观来说就是有多少个状态就有多少比特&#xff0c;除了有效的比特为1外&#xff0c;其他都为0. 2. 独热编码过程 &#xff08;1&#xff09;将分类值映射到整数…

Simulcast与SVN

什么是Simulcast: 一个客户端向服务器发送高清&#xff0c;标清&#xff0c;低清三种视频流&#xff0c;服务器根据其他接收客户端的带宽情况分发不同的视频流。Simulcast不仅有客户端的工作&#xff0c;还有服务器的工作。 开启Simulcast的三种方式: Munging SDP方式 添加assr…

网络实验①——同Vlan下相互通信

实验要求&#xff1a; pc0与pc1互通pc2与pc3互通实验步骤&#xff1a; A交换机配置&#xff1a; enable config t hostname switch-A vlan 10 vlan 20 exit interface f0/1 switch access vlan 10 no shutdown interface f0/2 switch access vlan 20 no shutdown interface f0/…