堆、栈、方法区
下面这张图,是这三个部分的大体演示:
堆
一个 JVM 实例只存在一个堆,堆内存的大小是可以调节的,类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行
新生代
刚创建的对象,都是放在新生代中的,新生代的 GC 询问比较频繁,过一会,就会检查这个对象是否需要被回收
老年代
如果一个新生代中的对象,经过了 15 次 GC 访问,都没有被回收,那么,这个对象,就会被转移到老年代中。老年代的 GC 询问就没有那么频繁了
永久代
不 GC,只要程序不关闭,那就一直放在内存中,我们的常量、类信息(Class),方法,接口(Interface)等,就是放在永久代中的
栈
Java栈的区域很小 , 大概2m左右 , 特点是存取的速度特别快 栈存储的特点是, 先进后出
存储速度快的原因:
栈内存, 通过 ‘栈指针’ 来创建空间与释放空间 !
指针向下移动, 会创建新的内存, 向上移动, 会释放这些内存 !
这种方式速度特别快 , 仅次于PC寄存器 !
但是这种移动的方式, 必须要明确移动的大小与范围 ,
明确大小与范围是为了方便指针的移动 , 这是一个对于数据存储的限制, 存储的数据大小是固定的 , 影响了程序 的灵活性 ~
所以我们把 更大部分的数据 存储到了堆内存中
存储的是:
基本数据类型的数据 以及 引用数据类型的引用!
例如:
int a =10;
Person p = new Person();
存储在栈内存中 , 第二句代码创建的对象的引用§存在栈内存中
方法区
存放的是
- 类信息
- 静态的变量
- 常量
- 成员方法
方法区中包含了一个特殊的区域 ( 常量池 )(存储的是使用static修饰的成员)
方法区,又称为永久代,又称为非堆区
方法区被所有线程共享:
这些区域存储的是:静态变量+常量+类信息(构造方法、接口定义)+运行时常量池
注意:实例变量存在堆内存中,和方法区无关 (就是 new 出来的部分)
小结
- 堆
- 存储的是对象,每个对象都包含一个与之对应的class
- JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
- 对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定
- 栈
- 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)
- 每个栈中的数据(原始类型和对象引用)都是私有的
- 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
- 数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失
- 方法区
- 静态区,跟堆一样,被所有的线程共享
- 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量