【Mark学Java】Java中的堆 栈 方法区
JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)
首先要明确堆
是堆(heap)
,栈
是栈(stack)
,堆栈
是栈
。
那么什么是 堆 栈,看看Oracle官方解释
Stack(栈)
原文
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
翻译
每个Java虚拟机线程都有自己的私有Java虚拟机栈,与该线程同时创建.与C语言中的栈相似,Java虚拟机栈保存局部变量,部分结果,并在函数调用和返回时起作用.Java虚拟机栈不被直接操作(除pop,push外),因此可以为堆分配帧…Java虚拟机栈内存不是连续的
函数调用的局部状态之所以用栈来记录是因为这些数据的存活时间满足后入先出”(LIFO)
顺序,而栈的基本操作正好就是支持这种顺序的访问。
举例说,假如有下面程序:
int main() {
a();
return 0;
}
void a() {
b();
}
void b() {
c();
}
void c() {
}
那么整个程序的函数活动时间可以表示为:
main() a() b() c()
- main()
|
+> - a()
. |
. +> - b()
. . |
. . +> - c()
. . . |
. . + <- return from c()
. . |
. + <- return from b()
. |
+ <- return from a()
|
- return from main()
可以看到,函数的调用有完美的嵌套关系
——调用者
的生命期总是长于被调用者
的生命期,并且后者在前者的之内。这样,被调用者的局部信息所占空间的分配
总是后于调用者的(后入
),而其释放
则总是先于调用者的(先出
),所以正好可以满足栈的LIFO顺序
,选用栈
这种数据结构来实现调用栈是一种很自然的选择。
特点
-
每个线程包含一个栈区,栈中只保存方法中(不包括对象的成员变量)的
基础数据类型
和自定义对象的引用
(不是对象),对象都存放在堆区中 - 每个栈中的数据(
原始类型
和对象引用
)都是私有
的,其他栈不能访问。 - 栈分为3个部分:
基本类型变量区
、执行环境上下文
、操作指令区(存放操作指令)
。
Heap(堆)
原文
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor’s system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.
翻译
Java虚拟机具有一个在所有Java虚拟机线程之间共享的堆。 堆是运行时数据区,从中分配所有类实例和数组的内存。
堆是在虚拟机启动时创建的。 自动存储管理系统(称为垃圾收集器)可以回收对象的堆存储; 对象永远不会显式释放。 Java虚拟机不假定特定类型的自动存储管理系统,可以根据实现者的系统要求选择存储管理技术。 堆的大小可以是固定的,也可以根据计算的要求进行扩展,如果不需要更大的堆,则可以将其收缩。 堆的内存不必是连续的。
JVM里的堆
特指用于存放Java对象
的内存区域。所以根据这个定义,Java对象全部
都在堆上。要注意,这个“堆”并不是数据结构意义上的堆(Heap (data structure),一种有序的树
),而是动态内存分配意义上的堆——用于管理动态生命周期的内存区域。JVM的堆被同一个JVM实例中的所有Java线程共享
。它通常由某种自动内存管理机制所管理,这种机制通常叫做垃圾回收
(garbage collection,GC)。JVM规范并不强制要求JVM实现采用哪种GC算法。
特点
- 存储的全部是
对象实例
,每个对象都包含一个与之对应的class的信息
(class信息存放在方法区)。 - jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放
对象本身
,几乎所有的对象实例
和数组
都在堆中分配。
与堆区别
-
堆
的优势是可以自动分配内存
的大小,生存期也不用实告诉变异器,java的垃圾回收器会自动回收
这些不用的数据。缺点是由于要动态的分配内存,存储效率会比较的慢
。 - 栈的优势是
存取效率比较快
,仅次于寄存器,栈数据可以共享
。但缺点是栈中的数据大小和生存期的固定
的,缺乏灵活性。
方法区
方法区(Method Area)
,与Java堆一样是各个线程共享
的内存区域。用于存储被JVM加载的类信息
、常量
、静态变量
、即时编译器编译后的代码
等数据。
虽然Java虚拟机规范将方法区描述为堆的一个逻辑部分,但是它却有个别名叫做Non-Heap(非堆)
,目的就是和Java堆区分开来。Java虚拟机规范对方法区的限制十分宽松,除了和Java堆一样不需要连续的内存空间
分配和可选择固定大小或可拓展内存
以外,方法区也可以被垃圾回收器管理或不受其管理。
在Java7
以前,HotSpot虚拟机
中,方法区也被称为“永久代
”,因为在物理上,方法区使用的是由JVM开辟的堆内存,由于和Java堆共享内存且内存空间由垃圾收集器统一分配和管理,自然的垃圾收集也拓展到了方法区上。此时,Java堆中分区为青年代Young Generation
和老年代Old Generation
,而方法区自然地被称为永久代Permanent Generation
。
在Java8
中,HotSpot虚拟机改变了原有方法区的物理实现,将原本由JVM管理内存的方法区的内存移到了虚拟机以外的计算机本地内存
,并将其称为元空间(Metaspace)
。这样一来,现在的方法区实际存储在于元空间,再也不用和Java堆共享内存了,“永久代”也就永久地被撤销了。
特点
方法区:
- 又叫
静态区
,跟堆一样,被所有的线程共享。 - 它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
快速记忆java内存
是分为堆
,栈
和方法区
。
堆
中分配的是对象
,也就是new
出来的东西。
栈
中分配的是基本类型
和自定义对象的引用
。
方法区
存放的是类信息
和static变量
。
通过下述例子,进一步加深概念.
例
对于一个方法
public void Method1()
{
int i = 4;
int y = 2;
class1 cls1 = new class1();
}
上一篇: 实例详解php如何生成zip文件类
下一篇: 第二章-数据结构之链表