首页 > 其他分享 >JVM(方法区包含常量池及StringTable)

JVM(方法区包含常量池及StringTable)

时间:2024-10-27 17:10:18浏览次数:6  
标签:ab String 池及 StringTable 串池 内存 JVM 字符串 常量

方法区

(此图省略了栈等结构,JVM结构详细图在JVM简介中,方法区中常量池应为运行时常量池)

定义

方法区(Method Area)是Java虚拟机(JVM)的一部分,它与Java堆一样,是被JVM实例中所有线程共享的区域。方法区在JVM启动时创建,可以选择固定大小或允许动态扩展。这个区域的大小直接影响到系统能够保存的类数量,如果定义了过多的类,可能会导致内存溢出(OOM)错误。随着JVM的关闭,方法区占用的内存也会被释放。

在JDK 7及以前的版本中,方法区通常被称为永久代(PermGen),但在JDK 8及以后,永久代的概念被废弃,转而使用本地内存中实现的元空间(Metaspace)来替代。与永久代不同,元空间的大小默认情况下不受JVM内存的限制,而是使用本地内存,因此可能会耗尽所有可用的系统内存。(引用百度及几篇博客)

内存溢出

  • 1.8以前内存溢出(永久代)
    报错内容: java.lanng.OutOfMemoryError: PermGen space

  • 1.8以后内存溢出(元空间)
    报错内容:java.lanng.OutOfMemoryError: metaspace

场景
  1. 动态生成类的数量过多
    场景描述:在应用程序中使用了大量动态生成的类,比如使用反射、动态代理或字节码生成工具(如 ASM、CGLIB、Javassist)创建大量类。
    示例:某些框架(如 Hibernate、Spring 等)会在运行时创建代理类,如果没有合理限制,可能会导致方法区的内存被耗尽。
  2. 使用大量的字符串常量
    场景描述:应用中存在大量的字符串常量,特别是在运行时生成的字符串常量可能会导致方法区的内存占用增加。
    示例:通过拼接字符串或使用大量的字面量字符串,可能在方法区中生成多个相同的字符串对象。
  3. 类的重复加载
    场景描述:在某些复杂的应用中,特别是使用多个类加载器的情况,可能导致同一个类被加载多次,从而占用更多的内存。
    示例:使用 OSGi 框架或某些应用服务器时,类可能被多次加载,增加了方法区的内存消耗。
  4. 未被及时回收的类
    场景描述:当类被卸载的条件不满足时,即使类的实例已经被销毁,方法区中的类仍然存在,导致内存使用的增加。
    示例:长期运行的应用(如服务器)如果不断加载新类而不卸载旧类,可能会导致方法区的内存消耗逐渐增加。
  5. 过多的常量池
    场景描述:每个类在方法区中都有自己的常量池,常量池中存储了类的常量值,如果常量过多,可能导致内存溢出。
    示例:使用大量的注解,特别是当注解中包含大量数据时,会增加常量池的内存占用。
  6. 配置不当的 JVM 参数
    场景描述:方法区的大小可以通过 JVM 参数进行配置。如果配置的内存太小,可能在正常使用情况下就会出现内存溢出。
    示例:在启动 JVM 时未合理配置 -XX:PermSize 和 -XX:MaxPermSize(对于 Java 7 及之前的版本),可能导致方法区内存溢出。

解决方法

  • 优化类的生成和加载:尽量减少动态生成类的数量,合理使用代理和反射。
  • 控制字符串常量的数量:避免在运行时生成过多的字符串常量。
  • 合理配置 JVM 内存参数:根据实际应用需求调整方法区的大小。
  • 使用类卸载:在适当的情况下,确保类能够被及时卸载。
  • 监控与分析:使用监控工具(如 JVisualVM、JConsole)监测方法区的内存使用情况,以便及早发现和解决问题。

运行时常量池

定义

  • 常量池: 就是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息

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

StringTable(字符串常量池简称“串池”)

StringTable的特性

  • 常量池中的字符串仅是符号,第一次用到时才变为对象
  • 利用串池的机制来避免重复创建字符串对象
  • 字符串变量拼接的原理是StringBuilder(1.8)
  • 字符串常量拼接的原理是编译器优化
  • 可以用intern方法,主动将串池中还没有的字符串放入串池

面试题代码

String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";//ab
String s4 = s1 + s2;  //new String("ab")
String s5 = "ab";
String s6 = s4.intern();

//问
System.out.println(s3 == s4);//false
System.out.println(s3 == s5);//true
System.out.println(s3 == s6);//true

String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();

//问,如果调换了【最后空两行代码的位置呢】,如果是jdk1.6呢   true  false
System.out.println(x1 == x2)//false

常量池与串池的关系

字符串变量拼接

String s1 = "a";//创建一个a字符串类型,放入StringTable
String s2 = "b";//创建一个b字符串类型,放入StringTable
String s3 = "ab";//创建一个c字符串类型,放入StringTable
//StringTable['a','b','ab']
String s4 = "a" + "b"; //这段代码创建了一个StringBuilder对象
//new StringBuilder().append("a").append("b").toString()
System.out.println(s4 == s3)//答案是错误的的,s4在堆中,s3在串池中,不是一个对象

编译期优化

String s1 = "a";
String s2 = "b";
String s3 = "ab";
String s5 = "a" + "b";//javac在编译期间的优化,直接在串池中找到了“ab”
System.out.println(s4 == s3)//答案是true

intern

  • 1.8将这个字符串尝试放入串池,如果有则不会放入,如果没有则放入串池,会把串池中的对象返回
//StringTable["a","b"]
String s = new String("a") + new String("b");
//堆 new String("a")  new String("b")  new String("ab")
String s2 = s.intern();
//StringTable["a","b","ab"]
System.out.println(s == "ab");//true
System.out.println(s2 == "ab");//true
String x = "ab";
String s = new String("a") + new String("b");
String s2 = s.intern();
Systen.out.println(s == x);//false s在堆中,串池中有ab不会把s放入
Systen.out.println(s2 == x);//true s2为串池返回的ab
  • 1.6将这个字符串尝试放入串池,如果有则不会放入,如果没有则把对象复制一份放入串池,会把串池中的对象返回
String s = new String("a") + new String("b");
String s2 = s.intern();
String x = "ab";
Systen.out.println(s == x);//false s在堆中,串池中的ab是复制的另一个对象
Systen.out.println(s2 == x);//true s2为串池返回的ab

位置

  • 1.6在永久代中
  • 1.8在堆中
    详情在本文第一张图片

垃圾回收

StringTable会发生垃圾回收

性能调优

  • 调整 -XX:StringTableSize = 桶个数
  • 考虑字符串对象是否入池

参考学习视频为黑马程序员JVM课程地址:https://www.bilibili.com/video/BV1yE411Z7AP?p=1

标签:ab,String,池及,StringTable,串池,内存,JVM,字符串,常量
From: https://www.cnblogs.com/Wylie1207/p/18501507

相关文章

  • 2024年最新互联网大厂精选 Java 面试真题集锦(JVM、多线程、MQ、MyBatis、MySQL、Redis
    前言春招,秋招,社招,我们Java程序员的面试之路,是挺难的,过了HR,还得被技术面,在去各个厂面试的时候,经常是通宵睡不着觉,头发都脱了一大把,还好最终侥幸能够入职一个独角兽公司,安稳从事喜欢的工作至今...近期也算是抽取出大部分休息的时间,为大家准备了一份通往大厂面试的小捷径,准备......
  • 高级java每日一道面试题-2024年10月24日-JVM篇-说一下JVM有哪些垃圾回收器?
    如果有遗漏,评论区告诉我进行补充面试官:说一下JVM有哪些垃圾回收器?我回答:1.Serial收集器特点:Serial收集器是最古老、最稳定的收集器,它使用单个线程进行垃圾收集工作。在进行垃圾回收时,它会暂停所有用户线程,即StopTheWorld(STW)。单线程工作,适合单核CPU。在年......
  • 高级java每日一道面试题-2024年10月23日-JVM篇-说一下JVM有哪些垃圾回收算法?
    如果有遗漏,评论区告诉我进行补充面试官:说一下JVM有哪些垃圾回收算法?我回答:在Java虚拟机(JVM)中,垃圾回收(GarbageCollection,GC)是一项非常重要的功能,用于自动管理应用程序的内存。JVM采用多种垃圾回收算法来决定何时以及如何回收不再使用的对象所占用的内......
  • JVM:初识JVM
    目录一、什么是JVM?1、JVM的全称2、JVM的职责二、JVM的功能1、解释字节码文件(上面提到了)2、内存管理3、即时编译(Just-In-Time,简称JIT)三、常见的JVM1、常见的几种JVM2、HotSpot(OracleJDK版)的发展历程总结一、什么是JVM?1、JVM的全称JVM全称是JavaVirtualMac......
  • JVM、JDK、JRE的区别是什么
    在探讨Java编程语言及其环境时,我们会经常遇到JVM、JDK、JRE这三个词。每个词都有自己特定的定义和角色。让我们详细了解一下这三者之间的区别。Java虚拟机(JVM)是Java平台的一部分,负责执行Java字节码。Java运行环境(JRE)是运行Java程序所需的环境。Java开发工具包(JDK)是Java的开发环境......
  • JVM内存池监控
    1.Committed1.1定义:committed指的是JVM从操作系统那里已经获取并承诺给内存池使用的内存量。这部分内存已经被分配给JVM,并且可以立即用于存储对象或数据。1.2特点:committed内存不一定全部被使用,但它保证了JVM在需要时可以直接使用这些内存而不需要再向操作系统申请。当......
  • JVM - 清单
    JVM内存布局是怎样的Java对象的布局是怎么样的对象分配策略是怎么样,什么是空间分配担保机制GCroots有哪些ThreadLocal内存泄漏的原因GC算法有哪些,垃圾收集器有哪些,各自特点类的生命周期类Class对象被回收的条件有哪些类加载器,什么是双亲委派流程......
  • JVM
    JVM构成及相关开发注意一、前言JVM也就是JavaVirtualMachine,即Java虚拟机。我们常用过的虚拟机比如VMware,属于系统虚拟机,完全对物理计算机的仿真,提供一个可运行完整操作系统的平台。而Java虚拟机则为程序虚拟机,专门设计为执行某些计算机程序而实现,在Java虚拟机内执行的是J......
  • 【JVM神秘大门】Java虚拟机原理保姆式教学,零基础速成GC机制(下篇)
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • oom排查与jvm部门知识
    1)什么是OOM?OOM,全称“OutOfMemory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明:ThrownwhentheJavaVirtualMachinecannotallocateanobjectbecauseitisoutofmemory,andnomorememorycouldbemadeavailablebyt......