java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java常量池堆和栈

Java中常量池、堆和栈的区别对比与联系

作者:Wokoo7

Java中堆存储对象实例和字符串(JDK7+),栈保存方法调用信息与局部变量,常量池缓存编译期常量,三者通过引用关联,堆与栈区分对象创建与存储,常量池优化内存复用,本文给大家介绍Java中常量池、堆和栈的区别对比与联系,感兴趣的朋友一起看看吧

在 Java 中,常量池、堆、栈是 JVM 内存模型中三个核心的内存区域,各自承担不同的职责,其位置、存储内容和特性有显著区别,但又相互关联。下面详细解析:

一、基本概念与存储内容

1. 堆(Heap)

2. 栈(虚拟机栈,VM Stack)

3. 常量池(Constant Pool)

常量池并非单一区域,而是一个 “存储常量的集合”,细分为Class 常量池、运行时常量池、字符串常量池,其位置和作用不同:

类型位置(JDK8+)存储内容
Class 常量池.class 文件中(加载后进入元空间)类编译时生成的常量,如字面量(字符串、数字)、符号引用(类名、方法名)等。
运行时常量池元空间(本地内存,方法区实现)Class 常量池加载到内存后的表现形式,常量在此处被解析为直接引用(如对象地址)。
字符串常量池堆内存存储字符串字面量(如"abc"),用于复用相同内容的字符串,减少内存消耗。

二、三者的区别

维度堆(Heap)栈(VM Stack)常量池(以字符串常量池为例)
存储内容对象实例、数组、字符串常量池(JDK7+)局部变量、栈帧(方法调用信息)字符串字面量、基本类型常量等
线程共享性线程共享(所有线程可访问同一对象)线程私有(每个线程有独立的栈)字符串常量池线程共享;Class 常量池随类加载,线程共享
内存管理由垃圾回收器(GC)回收随线程 / 方法结束自动释放(栈帧弹出)字符串常量池中的常量在无引用时被 GC 回收
内存大小大(可动态扩展)小(固定,易栈溢出)中等(依赖常量数量)
访问速度慢(内存不连续,需 GC 管理)快(内存连续,无 GC 干预)较快(复用机制减少创建开销)
生命周期随对象引用存在而存在随线程或方法调用周期存在随类加载 / 常量创建而存在,无引用时销毁

三、三者的联系

三个区域并非孤立,而是通过 “引用” 相互关联,共同支撑 Java 程序的运行:

  1. 栈 → 堆:栈中的局部变量(引用类型)指向堆中的对象。
    例如:String s = new String("abc")中,s是栈中的局部变量,指向堆中new String("abc")创建的对象。

堆 → 字符串常量池:堆中的字符串对象可能引用字符串常量池中的字面量。

四、举例说明三者关系

public class MemoryDemo {
    public static void main(String[] args) {
        // 1. "hello"放入字符串常量池(堆中);
        //    s1(栈中)引用常量池中的"hello"
        String s1 = "hello"; 
        // 2. 堆中创建新对象(内容为"hello"),该对象引用常量池中的"hello";
        //    s2(栈中)指向堆中的新对象
        String s2 = new String("hello"); 
        int a = 10; // 3. a是局部变量,直接存储在栈的局部变量表中
    }
}

五、字符串常量池与堆内存

重要判断技巧: 

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "hello";
    String s3 = new String("hello");
    String s4 = new String("hello");
    System.out.println(s1 == s2);    // true
    System.out.println(s1 == s3);    // false
    System.out.println(s3 == s4);    // false
}

总结

到此这篇关于Java中常量池、堆和栈的区别与联系的文章就介绍到这了,更多相关java常量池堆和栈内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文