JVM复习总结2024.4.18(很重要)

一、

1. 基于JDK1.8的String intern()方法解析

intern方法 1.8

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

  • 如果串池中没有该字符串对象,则放入成功
  • 如果有该字符串对象,则放入失败

无论放入是否成功,都会返回串池中的字符串对象

1. 示例一

String s2 = s.intern();

当执行 String s2 = s.intern(); 时,会遵循以下逻辑:

  • 如果字符串s已经在常量池中存在,那么s2会被设置为指向常量池中已存在的相同字符串的引用。
  • 如果字符串s不在常量池中,它的内容会被复制到常量池,并且s2被设置为指向这个新添加到常量池的字符串的引用。

这段代码的主要目的是确保s2常量池中s相同内容的字符串的一个引用,这样可以优化内存使用,特别是当你有一个可变的对象但希望它在后续的操作中像一个不可变的常量一样行为时。

总结:不管放入成功还是失败,s2始终是字符串常量池中的对象。

2. 示例二

String s = new String("a")+new String("b");
String s2 = s.intern();
System.out.println(s == "ab");//true
System.out.println(s2 == "ab");//true

执行第一行时,创建的s对象是堆中的。

执行第二行时,字符串常量池中还没有与s相同内容的字符串对象,即还没有“ab”对象,则放入成功,于是第三行输出为true,因为已经放入成功了。(注意:这里的“放入成功”是指将堆中的s对象放入到了字符串常量池中了,堆中不再有s对象了

3. 示例三

String s1 = "ab";
String s = new String("a")+new String("b");
String s2 = s.intern();
System.out.println(s == "ab");//false
System.out.println(s2 == "ab");//true

执行第三行时,字符串常量池中已经存在与s相同内容的字符串对象,即已有“ab”对象,则放入失败,于是第四行输出为false,因为放入失败了。至于s2,不管放入成功还是失败,都会是字符串常量池中的常量“ab”指向它的一个引用。

注意:JDK1.6的intern()方法与JDK1.8有不同哦。不同之处在于,1.6中放入时,如果串池中没有,则拷贝一份放入串池,相当于此时堆中和串池各有一份。

三、问GitCode

1. JVM 方法区

JVM 方法区,也被称为非堆(Non-Heap),是Java虚拟机的内存区域之一,主要用于存储已由虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它是线程共享的,这意味着所有线程都会访问同一个方法区。

主要特点

  1. 存储内容包括类型信息、域(Field)信息、方法(Method)信息、运行时常量池等。
  2. 方法区在JVM启动时创建,其物理内存空间可以是不连续的。
  3. 大小可固定或可扩展,但过度填充会导致内存溢出,如java.lang.OutOfMemoryError: PermGen space(JDK 7及之前)或java.lang.OutOfMemoryError: Metaspace(JDK 8及之后)。
  4. 类只能被加载一次,保证了类的全局唯一性。

发展历程

  • 在早期的HotSpot JVM中,方法区被称为永久代(Permanent Generation),使用特定的空间进行管理。
  • JDK 8开始,永久代被元空间(Metaspace)取代,元空间主要利用操作系统的native memory,允许更大的灵活性和更好的性能。

内存分配

  • 字符串常量池在JDK 7之前位于永久代,JDK 8后移到了Java堆中。
  • 静态变量存储在方法区内,对于static final类型的变量,如果其值是编译期常量,则会放入运行时常量池。

垃圾回收

  • 方法区中的一些内容,如不再使用的类、无引用的常量,会被垃圾收集器清理,这称为类卸载。
  • 类卸载条件较为苛刻,通常发生在系统资源紧张时。

相关问题

  1. 方法区和Java堆的主要区别是什么?
  2. 为什么在JDK 8中要将字符串常量池从永久代移出来?
  3. 什么是运行时常量池,它与字面量池有何联系?
  4. 系统如何判断一个类是否可以被卸载?
  5. 如何通过配置JVM参数调整方法区(元空间)的大小?

2. JDK1.7和JDK1.8对应的方法区分别存哪些内容?★★★★★

在JDK 1.7中,方法区(也称作永久代)主要存储以下内容:

  • 类的信息:如类名、超类名、接口实现等。
  • 域(Field)信息:类的成员变量及其相关信息。
  • 方法信息:类的方法签名、访问权限等。
  • 运行时常量池:存储各种常量,包括字符串常量、数字常量以及符号引用等。
  • 类装载器和权限验证相关数据。
  • 静态变量:类级别的变量。
  • 编译后的字节码指令。

而在JDK 1.8中,由于永久代被元空间(Metaspace)替代,存储的内容大致相同,但有以下几个变化:

  • 字符串常量池被移出方法区,现在存储在Java堆中。
  • 元空间主要利用操作系统内存,而不是JVM堆的一部分,因此避免了永久代可能导致的内存溢出问题。
  • 其他如类信息、字段信息、方法信息、运行时常量池(不含字符串常量)等仍然存储在元空间中。

JVM JDK1.8中静态变量保存在哪里?

在JDK 1.8中,静态变量属于类的一部分,因此它们存储在方法区域(Metaspace)中,这个区域也被称为元空间。元空间主要存储类的元数据,包括类的结构信息、方法信息以及静态变量。当类加载时,这些静态变量会被加载到元空间,并且在所有实例化对象之前就可以访问。

JVM JDK1.8对应的方法区分别存哪些内容?

在JDK 1.8中,原本的方法区(Method Area)被概念上替换为元空间(Metaspace)。以下是JDK 1.8中元空间的主要内容:

  • 类的版本信息(major version number)
  • 类名、接口名
  • 父类的全限定名
  • 接口的直接父接口
  • 常量池(包括字符串常量池,但现在字符串常量池已被移动至堆中)
  • 字段的名称、类型、访问权限
  • 方法的名称、返回类型、参数类型、访问权限、是否是桥接方法、是否是默认方法等
  • 访问标志,用于判断某个类或方法是否可被访问
  • 类装载器信息

综上,方法区存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译出来的代码等数据。只是JDK1.8及之后,字符串常量池不再放在方法区了,而是放到了堆中。

3. 字符串常量池和运行时常量池有什么区别?

字符串常量池和运行时常量池都是JVM内存模型的一部分,它们的区别在于作用范围和包含的内容:

作用范围

  • 字符串常量池:主要存储字面量字符串(比如"hello")以及用String.intern()方法添加的字符串。
  • 运行时常量池:属于方法区的一部分,存储编译期生成的各种字面量和符号引用,这些字面量包括但不限于数字、字符串、方法签名等。

引入时间

  • 字符串常量池:在程序执行前就可能存在,如静态初始化块中的字符串。
  • 运行时常量池:随着类加载到JVM中而创建,随着类的卸载而销毁。

内容类型

  • 字符串常量池:仅包含字符串。
  • 运行时常量池:包含各种字面量和符号引用,不只是字符串。

优化行为

  • 字符串常量池:通过intern()方法可以保证同一字符序列的字符串只存在于池中的一次,提高内存效率。
  • 运行时常量池:解析符号引用为直接引用,优化方法调用速度。

4. 字符串常量池在JDK 1.8中的位置变化带来什么影响?

在JDK 1.8中,字符串常量池的位置从永久代移动到了堆内存中,这一改变带来了以下影响:

  • 内存分配更加灵活:使用堆内存来存储字符串常量使得内存管理更为灵活,可以根据程序需要动态调整大小,降低了永久代溢出的风险。
  • 更少的垃圾回收压力:在元空间中,主要是存放类的元信息,这些信息在类加载时创建且生命周期与类相同,不会频繁变动。而字符串常量在堆中则会随着对象的创建和销毁进行GC,减少了对元空间的垃圾回收压力。
  • 提高性能:对于字符串拼接操作,JDK 1.8会更早地将它们放入堆中,当字符串连接的结果是常量时,可以直接指向常量池,提升了性能。
  • 优化内存使用:由于元空间主要使用的是 Native Memory,移动字符串常量池到堆中可以节省这部分系统内存资源。
  • 减少了 PermGen OutOfMemoryError 的出现:在JDK 1.7中,如果字符串常量池占用的空间过大,可能会导致永久代溢出,而在JDK 1.8中这种问题得到了缓解。

5. 为什么说JDK 1.8的字符串常量池优化了内存使用?

在JDK 1.8中,字符串常量池位于堆内存而不是元数据区域(元空间),这优化了内存使用的几个方面:

  • 按需分配:堆内存是Java应用程序的主要内存区域,其大小可以根据应用需求动态扩展。这意味着字符串常量池也可以随着程序运行按需分配空间,避免一次性分配过多内存。

  • 减少元空间压力:元空间主要用于存储类的元数据,如方法和字段的信息。将字符串常量池移出元空间减轻了这个区域的压力,减少了因元空间满而引发的内存溢出风险。

  • 更有效的垃圾回收:堆内存中的对象更容易被垃圾收集器处理。一旦不再有引用指向某个字符串实例,垃圾收集器就会回收这部分内存,提高了内存利用率。

  • 更佳的内存碎片管理:堆内存在垃圾回收过程中会进行整理,降低内存碎片,从而提高整体的内存使用效率。

  • 与对象共享:JDK 1.8中,如果两个不同的字符串变量具有相同的值,那么它们在堆中只会有一个实例,这是通过 intern() 方法实现的。这样可以有效地避免重复的对象创建,节约内存。

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

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

相关文章

数据库-Redis(18)

目录 86.Redis 分布式锁的实现?什么是RedLock? 87.Redis缓存有哪些问题,如何解决? 88.Redis性能问题有哪些,如何分析定位解决?

短视频批量采集提取软件|视频下载工具

短视频批量采集提取软件:高效获取视频资源 一、开发背景 在日常业务中,我们经常需要获取大量的短视频资源,以支持各种需求,但传统的获取方式过于繁琐,一一复制链接下载效率低下。基于此需求,我们开发了一…

Jenkins机器已经安装了ansible, 运行的时候却报错ansible: command not found

操作系统:MacOS Jenkins log提示 ansible: command not found 直接在Jenkins 机器中,进入一样的目录执行ansible --version OK 原因: Jenkins 默认使用的环境是 /usr/bin, 而我的ansible 安装配置在conda3 下面,所以需要在Jenkin…

【工位ubuntu的配置】补充

软件 安装桌面图标的问题 登录密码 root的密码为:19980719 按照如下的链接进行配置: https://blog.csdn.net/zhangmingfie/article/details/131102331?spm1001.2101.3001.6650.3&utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7E…

Meta发布新AI模型Llama 3,包含80亿和700亿参数

据Odaily星球日报报道,Meta旗下AIatMeta官方在X平台发文,Meta正式发布了包括80亿参数和700亿参数在内的2个新AI模型Llama 3。这些模型实现了新功能,如改进的推理能力,并为特定模型设定了新的最先进水平。在未来几个月,…

opencv图像转QPixmap格式图像后无彩色且中间有一条黑线

背景 自己使用PyQt5开发了一个界面,需要在界面的某个标签上显示opencv-python处理后的图像, 原来使用的代码段如下: img_rgb cv2.cvtColor(cvimage, cv2.COLOR_BGR2RGB)cv2.imwrite(2.jpg,img_rgb)qimg QImage(img_rgb.data, img_rgb.shape…

工业控制(ICS)---modbus

Modbus Modbus,市场占有率高、出题频率高,算是最常见的题目,因为这个协议也是工控领域最常见的协议之一,主要有三类 Modbus/RTU 从机地址1B功能码1B数据字段xBCRC值2B 最大长度256B,所以数据字段最大长度252B Modbus/ASCII …

DFS之剪枝2

给定两个整数 n , x n,x n,x。 你可以对 x x x 进行任意次以下操作: 选择 x x x 的一位数字 y y y,将 x x x 替换为 x y x \times y xy。 请你计算通过使用上述操作,将 x x x 变为一个 n n n 位数字(不含前导 0 0 0&…

C++笔记:引用

目录 概念: ​编辑 引用的特性: 引用中的权限问题: 引用与指针的区别: 引用的使用: 概念: 引用是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间。 引用的符号:&…

NLP(3)--利用nn反向计算参数

前言 仅记录学习过程,有问题欢迎讨论 获取数据 自定义一个方程,获取一批数据X,Y import matplotlib.pyplot as pyplot import math import sysX [0.01 * x for x in range(100)] Y [2*x**2 3*x 4 for x in X] print(X) print(Y) pyplot.scatter(…

KV Cache 技术分析

原文:Notion – The all-in-one workspace for your notes, tasks, wikis, and databases. 1 什么是KV Cache LLM(大型语言模型)中的 Attention 机制中的 KV Cache(键值缓存)主要作用是存储键值对,以避免在…

ChatGPT又多了一个强有力的竞争对手:Meta发布Llama 3开源模型!附体验地址

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,所以创建了“AI信息Gap”这个公众号,专注于分享AI全维度知识…

ChatPDF代码解读2

这段代码定义了一个名为`ChatPDF`的类,它结合了文本相似性模型和生成模型,用于处理和生成基于特定文档语料库的自然语言回答。以下是对代码的详细解读: 1. **导入依赖**:代码开始处导入了多个Python库,包括`argparse`(命令行参数解析)、`hashlib`(哈希函数)、`os`(操…

力扣:两数之和

知识点&#xff1a; 动态数组的创建&#xff1a; #include<stdlib.h> arr (int*)malloc(len * sizeof(int)); 如何使用sacnf输入数组&#xff1a; scanf 函数在读取输入时&#xff0c;会自动跳过空格&#xff08;空格、制表符、换行符等&#xff09;和换行符&#…

vscode绿绿主题setting config

下载插件Green Tree Theme 选greentree ctrl shift p找到setting {"workbench.colorTheme": "Green Tree","editor.fontSize": 16.5, // 字号"workbench.colorCustomizations": {"[Green Tree]": {"activityBarBadge.…

日志事件ID

日志排查时&#xff0c;通常会根据事件ID搜索日志。 1、安全日志 用户登录事件&#xff1a; 4624&#xff1a;登录成功 4625&#xff1a;登录失败 4634&#xff1a;注销本地登录用户 4647&#xff1a;注销远程登录的用户 4648&#xff1a;使用显式凭证尝试登录 4672&am…

用pigeon kotlin swift写一个自己的插件

文章目录 1. 创建一个flutter plugin项目2. 引入依赖3. 创建pigeons文件夹和message.dart4. 执行生成各个平台文件的命令5. base_plugin.dart6. BasePlugin.kt7. BasePlugin.swift8. 遇到的问题9. [源码](https://github.com/githubityu/base_plugin) 1. 创建一个flutter plugi…

算法一:数字 - 两数之和

给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 来源&#xff1a;力扣(LeetCode) 链接&#xf…

scala---基础核心知识(变量定义,数据类型,流程控制,方法定义,函数定义)

一、什么是scala Scala 是一种多范式的编程语言&#xff0c;其设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台&#xff08;Java虚拟机&#xff09;&#xff0c;并兼容现有的Java程序。 二、为什么要学习scala 1、优雅 2、速度快 3、能融合到hado…

管道流设计模式结合业务

文章目录 流程图代码实现pomcontextEventContextBizTypeAbstractEventContext filterEventFilterAbstractEventFilterEventFilterChainFilterChainPipelineDefaultEventFilterChain selectorFilterSelectorDefaultFilterSelector 调用代码PipelineApplicationcontrollerentitys…