`
臻是二哥
  • 浏览: 186894 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

JVM-常量池

    博客分类:
  • JVM
阅读更多
学习JVM之后,发现对常量池的理解又深入了一些。下面就从JVM的层面去理解JAVA程序中那些常见的语句。
读过笔者博客“JVM-类的生命周期“http://yizhenn.iteye.com/blog/2290619的读者都应该已经知道,JVM在加载class文件时经历了装载,连接,初始化的过程,其中连接又包括验证,准备和解析。我们就来说说这个解析。

所谓解析,就是将class文件中的静态常量池中的符号引用解析为直接引用,说白了,就是为class常量池中的一些常量创建对象。比如String str="abc";理论上来讲直接在class静态常量池中存放"abc"即可。但是我们知道,JAVA中除了8种基本类型之外,其他的都是引用。因此,对于静态常量池中的"abc",JVM会在堆中创建一个对象,静态常量池中的str就指向这个刚刚创建的对象。像str这样的常量对象所在的空间,叫做动态常量池。

在JAVA中,String和Integer,Short,Long,Character,Boolean,Byte这六种基本类型的封装类都实现了动态常量池机制。对于六种基本类型的封装类,我们以Integer为代表进行说明。

如下代码:
String a="123";
String b="123";

在解析的时候,发现静态常量池中有a="123",就会在动态常量池中寻找是否有值为"123"的对象,结果没有找到,就会执行new String("123"),然后使静态常量池中的a指向该对象,当发现静态常量池中有b="123",就会在动态常量池中寻找是否有值为"123"的对象,结果找到了之前创建的那个对象,就会把那个对象的地址返回给静态常量池中的b。

上面的过程是在解析的时候做的,当然你也可以认为在执行的时候做的。但不管怎样,一定存在一个常量池,当执行String str="xx";的时候,先到常量池中去寻找值为xx的对象,如果存在,就直接返回该对象地址,否则在动态常量池中创建一个新对象并返回地址。

如下代码:
String a=new String("123");
String b=new String("123");

第一行代码在执行的时候,JVM见到"123",会先到动态常量池中看是否有值为"123"的对象,如果没有,在常量池中创建一个对象String("123").这个过程和a没有半毛钱关系,你可以认为这是JVM常量池自学习的过程。接着,在堆区创建一个对象String("123");并将该对象的引用返回给a;
第二行代码也是这样的过程,所以上面的两行代码可能产生2或3个对象。

对于String类,还存在一个str.intern()方法,他的作用是检查动态常量池中是否存在值与str对象相同的对象,如果存在,直接返回该对象的引用。如果不存在,就在常量池中创建一个对象,然后返回他的引用。
如下代码:
String a="123";
String b="123";
String c=new String("123");
String d=c.intern();

对于上面的代码,你应该能理解,a和b和d都指向的是动态常量池中的那个对象String("123"),而c指向的是堆中的对象String("123");

介绍了String类的常量池,我们来说Integer类的常量池。Integer类型的取值不像String类型那么广泛,String常量池中的对象收集自程序。Integer常量池中的对象是固定的,只有取值为-128~127的这256个对象。当Integer.valueOf(i)中i的值是-128~127时,直接返回常量池中的对象,否则在堆区新建一个对象并返回他的引用。这可以从jdk源码中得到证明,在jdk源码中,Integer有这样的一个方法:
    public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }


这个方法是自动装包时候用的方法,何谓装包?把int这个基本类型转化为Integer这个引用类型就是装包。
代码如下:
Integer a=1;
Integer b=1;
Integer c=1111;
Integer d=1111;

对于上面的代码,实际上如下:
Integer a=Integer.valueOf(1);
Integer b=Integer.valueOf(1);
Integer c=Integer.valueOf(1111);
Integer d=Integer.valueOf(1111);

因此a和b指向Integer常量池中的同一个对象,他们的值相等。c和d指向堆区中的不同对象,他们的值不等。

如下代码:
Integer a=new Integer(1);
Integer b=new Integer(1);

由于使用了new,强制的在堆区创建了两个对象,没用到常量池优化,因此a和b的值不等。

这里顺便提一下装包和拆包,将基本类型转化为对应的封装类的过程叫装包,反之叫拆包。当基本类型和其对应的封装类执行比较的时候,比如Integer对象和int型比较,这会使用拆包,将Integer类型拆包为int,这个过程调用Integer的intValue()方法。

关于上面提到的其余5中包装类的常量池与Integer类似,在此不再赘述。
0
5
分享到:
评论

相关推荐

    第4节: 揭秘JVM字符串常量池和Java堆-01

    第4节: 揭秘JVM字符串常量池和Java堆-01第4节: 揭秘JVM字符串常量池和Java堆-01第4节: 揭秘JVM字符串常量池和Java堆-01第4节: 揭秘JVM字符串常量池和Java堆-01第4节: 揭秘JVM字符串常量池和Java堆-01第4节: ...

    weilei-JVM-ppt.rar

    8. **类文件结构**:分析.class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、接口索引等。 9. **JVM优化案例**:分享实际项目中遇到的问题及解决策略,比如内存泄漏、性能瓶颈等。 这些内容将有助于...

    JVM--字节码和类的加载篇1

    常量池中的符号引用,例如final常量的值、类和接口的全限定名、字段的名称和描述符、方法的名称和描述符,这些都是在解析阶段被转换成直接引用,以便JVM能够准确地定位和访问相应的内存地址。 总结起来,"JVM--字节...

    jvm-callgraph,jvm字节码的调用图生成器.zip

    字节码以二进制格式存储,包含了类的方法定义、操作符、常量池等信息。通过字节码,开发者可以跨越平台边界,实现“一次编写,到处运行”。 2. 调用图:调用图是一种图形表示法,用于描绘程序中的函数或方法调用...

    java技术面试必问:JVM-内存模型讲解.docx

    当类加载到内存后,JVM就会将class文件常量池中的内容存放到运行时常量池中;在解析阶段,JVM会把符号引用替换为直接引用(对象的索引值)。例如:类中的一个字符串常量在class文件中时,存放在class文件常量池中的...

    jvm基础知识与调优-jvm-training.zip

    - 方法区和运行时常量池:存储类和接口的常量、方法信息。 2. **内存管理** - 堆内存:主要分为新生代(Eden、Survivor空间)和老年代,新生代对象生命周期短,老年代对象生命周期长。 - 分代收集:不同代有不同...

    JVM常量池教程吐血整理干货.md

    ### JVM常量池详解 #### Class常量池(静态常量池) 在Java程序的编译过程中,每个`.class`文件都会包含一个常量池,这个常量池被称为Class常量池或者静态常量池。它存在于每个`.class`文件的`Constant Pool`部分...

    JDK8的JVM内存结构,元空间替代永久代成为方法区及常量池的变化1

    常量池分为静态常量池、运行时常量池、字符串常量池和整型常量池。静态常量池存在于每个*.class文件中,包含了字面量和符号引用,这部分在类加载的链接阶段会被解析成直接引用。运行时常量池则是在虚拟机运行时载入...

    JVM-CLASS文件分析脑图

    总结来说,JVM-CLASS文件分析脑图强调了class文件的结构细节,从文件头的魔术数到后面的常量池、类定义、字段和方法信息,以及属性表等,都是class文件的重要组成部分。通过分析这些结构,我们可以了解class文件如何...

    06-VIP-JVM调优实战及常量池详解(1)1

    当一个新字符串被创建时,JVM会检查常量池中是否存在相同的字符串,如果存在,就直接返回其引用,否则会在堆中创建一个新的实例并添加到常量池。 垃圾收集(Garbage Collection, GC)是JVM管理内存的重要机制。GC...

    jvm性能调优-jvm内存模型和优化-performance-jvm-memorymodel-optimize.zip

    5. **方法区(Method Area)/运行时常量池(Runtime Constant Pool)**:存储类的信息,包括类名、方法信息、常量等。这部分内存也参与垃圾回收。 二、内存模型优化 1. **堆内存优化**: - **对象创建优化**:...

    jvm -spark-优化

    - **Constant Pool OutOfMemory**:常量池溢出发生在常量数量过多时。可以通过增大永久代内存(在JDK 8中已改为元空间)来解决。 - **Direct Memory OutOfMemory**:直接内存溢出时发生。可以通过增加`-XX:...

    06-VIP-JVM调优实战及常量池详解(预习)1

    《JVM调优实战与常量池详解》 在Java开发中,JVM(Java虚拟机)的性能优化是一项至关重要的任务。通过对JVM进行调优,我们可以显著提升应用程序的运行效率,减少内存消耗,避免不必要的垃圾回收(GC)带来的性能...

    java-JVM-面试题

    - JDK 1.8:进一步优化了G1,移除了永久代,元空间使用本地内存,字符串常量池从 PermGen 移到了 Heap 的元空间。 4. **JVM参数设置** - `-XX:MaxPermSize`:在JDK 1.7及更早版本中,用于设置永久代的最大大小,...

    jvm-memory-view-0.93.162

    3. **方法区**:存储类的信息,如类的元数据、常量池等。在Java 8之后被元空间(Metaspace)取代,以减少对持久代的依赖。 4. **程序计数器**:记录当前线程执行的字节码指令地址,用于实现多线程的切换。 二、JVM...

    JVM图解-JVM指令-JVM原型图.rar

    - **方法区**(在Java 8后变为元空间):存储已加载类的信息,如类的元数据、常量池等。 - **虚拟机栈**:每个线程都有一个独立的虚拟机栈,用于存放方法调用时的局部变量表、操作数栈和方法出口等信息。 - **...

    java-JVM-面试题从基础到高级详解-HM

    3. **方法区**:存储类信息、常量、静态变量等,HotSpot中的永久代被元空间(Metaspace)取代。 4. **本地方法栈**:非Java方法(如C++ Native方法)的调用栈。 5. **垃圾收集**:包括可达性分析算法、标记-清除、...

    java8源码-jvm-study:jvm-study

    java8 源码 jvm-study 方法执行过程 jvm申请内存 初始化运行时数据区 方法区:存放 class;静态变量:常量 堆:实例对象 栈:栈帧(对象的引用,方法)...常量池(方法区) class常量池 class的方法 字面量(String a =

    B站河北王校长-Jvm-深度核心面试知识汇总.pdf

    - **原因**:常量池的容量计数值(constant_pool_count)是从1开始计数的,这意味着索引值范围从1到N。 - **目的**:这样做是为了方便处理一些特殊的情况,比如索引值为0可以表示“不引用任何常量池项目”。 - **...

Global site tag (gtag.js) - Google Analytics