在 Java 中,内存分配主要分为两大类,即栈内存和堆内存。它们各有用途,并且具备不同的特性。
- 栈内存: 用于在程序执行期间存储基本类型的局部变量、方法调用信息以及对象的引用。
- 堆内存: 用于存储实际的对象以及在运行时分配的动态数据。使用
new关键字创建的对象都存放在这里,该区域的内存由垃圾回收器进行管理。
Java
CODEBLOCK_3497a14d
输出结果
Employee ID: 101
Name: Maddy
Salary: 50000.0
Employee ID: 102
Name: Maddy
Salary: 60000.0
上述示例的内存表示图:
!stack内存表示图
- emp1 和 emp2: 引用存储在栈上。
- new Employee(…): 对象存储在堆中。
- "Maddy": 在字符串常量池(堆)中只存储一次。
- emp1.name 和 emp2.name: 都指向同一个字符串对象。
- display(emp1): 创建一个新的栈帧,参数 e 指向 emp1。
- (emp1.name == emp2.name): 结果为 true,因为它们引用的是同一个池化字符串。
栈内存分配
栈内存用于方法调用、局部变量和引用的存储。当方法启动时,内存会自动分配;当方法结束时,内存会自动清除。数据仅在方法执行期间存在。如果栈空间耗尽,就会发生 StackOverflowError(栈溢出错误)。
Java
CODEBLOCK_1d7a8181
输出结果
The sum is: 30
堆内存用于存储使用 new 关键字创建的对象和实例变量。其大小取决于类的结构。垃圾回收器通过移除未使用的对象来管理这一区域。
堆内存区域划分:
- 年轻代: 存储新创建的对象。
- 幸存区: 保存从 Eden 区经过垃圾回收后仍然存活的对象。
- 老年代: 存储生命周期较长的对象。
非堆内存区域:
- 元空间: 存储类的元数据,并使用本地内存(在 Java 8 中引入,替代了永久代)。
- 代码缓存: 存储经过 JIT 编译和优化的本地代码。
示例: 堆中的对象
Java
CODEBLOCK_3bf99098
在这里,INLINECODEb66ed043 对象位于堆中,而引用变量 INLINECODE56670477 位于栈中。
> 注意: 堆中的垃圾回收机制确保了内存的自动管理。
Java 中栈内存与堆内存的区别
堆内存
—
内存以任意随机顺序分配。
分配和释放是自动的(由垃圾回收器处理)。
成本较高
实现较为复杂
访问速度较慢
由于动态分配,可能会遭受内存碎片化的影响。
堆的内存局部性尚可,但不如栈高效
非线程安全,存储的数据对所有线程可见
堆可以根据需要进行调整大小
堆使用分层(树状)数据结构
链表中首选堆内存分配。
比栈内存大。