堆,栈,方法区,常量池,的概念
1.首先看堆,栈,方法区,常量池 的位置分布图


2、内存区域类型
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制;
2. 堆:存放所有new出来的对象;
3. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。);
4. 静态域:存放静态成员(static定义的);
5. 常量池:存放字符串常量和基本类型常量(public static final)。有时,在嵌入式系统中,常量本身会和其他部分分割离开(由于版权等其他原因),所以在这种情况下,可以选择将其放在ROM中 ;
6. 非RAM存储:硬盘等永久存储空间
Java中new对象时的JVM内存分配(简化版)
-
类检查:先检查类是否已加载,没有则先加载类
-
分配内存:
-
在堆内存中划分一块空间给新对象
-
两种分配方式:
-
指针碰撞(规整内存)
-
空闲列表(不规整内存)
-
-
-
初始化:
-
内存空间清零(默认值初始化)
-
设置对象头信息(哈希码、GC年龄等)
-
设置类型指针(指向类信息)
-
-
执行构造方法:
-
调用
<init>方法 -
按代码初始化对象属性
-
-
返回引用:将对象在堆中的地址返回给栈中的引用变量
3. 对象晋升老年代的规则
对象从年轻代进入老年代的 4 种情况:
-
年龄阈值
-
对象在 Survivor 区每熬过 1 次 Minor GC 年龄 +1
-
超过
-XX:MaxTenuringThreshold(默认 15)则晋升
-
-
大对象直接进入老年代
-
对象大小 >
-XX:PretenureSizeThreshold(默认 0,由收集器决定)
-
-
Survivor 区空间不足
-
Survivor 区中相同年龄的对象总大小 > Survivor 区一半空间
-
该年龄及以上对象直接晋升
-
-
动态年龄判定
-
HotSpot 优化规则:无需达到 MaxTenuringThreshold 也可能晋升
-
三、栈中放的东西,图示:

三、堆存放示意图:
对于String类的对象特别说明一下:

五,对于string的特殊解释
1 String s1 = "china";
2 String s2 = "china";
3 String s3 = "china";
4 String ss1 = new String("china");
5 String ss2 = new String("china");
6 String ss3 = new String("china");

1 int i1 = 9; 2 int i2 = 9; 3 int i3 = 9; 4 public static final int INT1 = 9; 5 public static final int INT2 = 9; 6 public static final int INT3 = 9;

1 class BirthDate {
2 private int day;
3 private int month;
4 private int year;
5 public BirthDate(int d, int m, int y) {
6 day = d;
7 month = m;
8 year = y;
9 }
10 省略get,set方法………
11 }
12
13 public class Test{
14 public static void main(String args[]){
15 int date = 9;
16 Test test = new Test();
17 test.change(date);
18 BirthDate d1= new BirthDate(7,7,1970);
19 }
20
21 public void change(int i){
22 i = 1234;
23 }
24 }

1 String s1 = "Hello";
2 String s2 = "Hello";
3 String s3 = "Hel" + "lo";
4 String s4 = "Hel" + new String("lo");
5 String s5 = new String("Hello");
6 String s6 = s5.intern();
7 String s7 = "H";
8 String s8 = "ello";
9 String s9 = s7 + s8;
10
11 System.out.println(s1 == s2); // true
12 System.out.println(s1 == s3); // true
13 System.out.println(s1 == s4); // false
14 System.out.println(s1 == s9); // false
15 System.out.println(s4 == s5); // false
16 System.out.println(s1 == s6); // true


一、Java 堆(Heap)
✅ 生命周期:
随 JVM 启动而创建,随 JVM 关闭而销毁。
所有线程共享堆内存。 所以多线程的时候会有安全问题
📌 特点:
存放对象实例(new 出来的对象)。
垃圾回收器(GC)主要管理区域。
可通过 -Xms 和 -Xmx 设置初始和最大堆大小。
二、Java 栈(Stack)
✅ 生命周期:
每个线程拥有自己的栈空间。
线程启动时创建栈,线程结束时栈被销毁。
📌 特点:
存储局部变量、方法参数、基本类型变量(如 int, boolean)和对象引用(reference)。
每个方法调用都会创建一个栈帧(Stack Frame),方法执行完毕后栈帧弹出。
🧠 示例:
public void method() { int a = 10; // 局部变量 a 存储在栈中 Person p = new Person(); // p 引用本身在栈中,实际对象在堆中 }
三、常量池(Constant Pool)
✅ 生命周期:
属于类的一部分,随类的加载而加载,类卸载时回收。
位于方法区(JDK 8 及之前)或元空间(JDK 8+)中。
📌 分类与特点:
1. 类文件常量池(Class 文件中)
存在于 .class 文件中,包含符号引用、字面量等信息。
2. 运行时常量池(Runtime Constant Pool)
类加载后,类文件中的常量池内容会被加载到运行时常量池。
支持动态添加内容(例如:String.intern())。
3. 字符串常量池(String Pool)
存放字符串字面量(如 "abc")。
JDK 7 开始移到堆中管理。
可通过 String.intern() 显式加入池中。
🧠 示例:
String s1 = "hello"; // 从字符串常量池获取或创建 String s2 = new String("hello").intern(); // intern() 将对象放入常量池
四、总结对比表

🔍 补充说明
栈内存不足:抛出 StackOverflowError。
堆内存不足:抛出 OutOfMemoryError: Java heap space。
常量池溢出(元空间不足):抛出 OutOfMemoryError: Metaspace(JDK 8+)。
你可以根据使用场景选择合适的数据结构和内存管理方式,避免内存泄漏或性能问题。


浙公网安备 33010602011771号