您的位置:首页 > 其它

JVM运行时内存区域

2017-03-31 11:21 155 查看
JVM运行java程序时会将内存划分为若干个不同的数据区域:

(1)程序计数器:

1、占用内存空间不大。

2、程序计数器相当于JVM所执行的字节码(jvm指令)的“行号指示器”,通过程序计数器的“值”找到吓一跳需要执行的字节码指令。

3、每一个线程所执行命令的顺序都是独立的,所以每个线程都有一个程序计数器。

4、此内存区域是唯一一个没有规定“OutOfMemoryError”的区域。

(2)虚拟机栈:

1、虚拟机栈是一个“栈结构”的内存区域(先进后出)。里面存的是一个个“栈帧”。

每一个方法在执行时都会创建一个栈帧。当方法在初始执行时其对应的栈帧进入虚拟机栈。当方法结束时,其栈帧出栈。

如:fun A(){ fun B()}

public void A(){
B();
}


其栈帧的执行顺序就是:A栈帧先入栈,B栈帧再入栈,等方法B执行完后,B栈帧再出栈,A栈帧再出栈。其整体过程也符合栈结构的“先进后出”。

2、每一个栈帧里存储了“局部变量表”,该表中存放了其对应方法在运行时所用到的“基本数据类型”、“对象引用”、“returnAdress”。

(long和double类型占用两个局部变量空间,其余类型只占用一个空间)。

3、局部变量表中的东西在“编译时”就能确定有哪些,所以在编译时,局部变量表所需的内存空间就能分配完成且方法运行期间不会改变。

4、该区域有两种异常:当请求的“栈深度”大于JVM虚拟机所允许的深度时,抛出“StackOverFlowError”。当内存不够时,抛出“OutOfMemmory”。

5、是线程私有的,生命周期与线程相同。

(3)本地方法栈:

1、与虚拟机栈唯一的区别是:

虚拟机栈是为“JVM执行java方法”而服务。

本地方法栈是为“JVM执行Native方法”而服务。

(3)java堆:

1、是JVM所管理的最大的一块内存。

2、所有线程共享。

3、用来存放“对象实例”(数组也是)。

4、并不是所有的对象都必须分配在堆上(逃逸分析、标量替换)。

5、java堆是JVM垃圾回收器的主要管理区域。

6、堆内存的大小可以是固定的,也可以是可扩展的。

7、当内存不够时,并且也无法再扩展时,抛出“OutOfMemmory”。

(4)方法区:

1、所有线程共享。

2、内存不够时抛出“OutOfMemmoryError”。

3、存放的是“类的信息”,包括类中的:

类的全路径名、类的直接超类的全限定名、类的修饰符、类的“常量池”、类的“域信息”、类的“方法信息”、类的final常量,类的“所有static静态变量”。

常量池:

每个类都有自己的常量池。常量池是“同一个类所用常量的集合”。如:

Integer a = 1;
Integer b = 1;
//a和b指向Integer类的常量池中的同一个内存空间(因为他们的常量都是1)。

//同理
String s1 = "hello";
String s2 = "hello";
System.out.print(s1==s2);
//输出的是“true”,因为s1和s2指向String类的常量池中同一个内存空间。

//以下不是常量池存储
String s3 = new String("hello");
String s4 = new String("hello");
System.out.print(s1==s2);
//输出的是“false”,因为s3和s4是对象实例,存与堆中不同的空间。


域信息:

jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序, 域的相关信息包括: 域名、域类型、域修饰符。

方法信息:

每一个类中都含有各种方法,所以方法区中会存储这些类中方法的相关信息,包括:

方法名、方法的返回类型、方法参数和类型、方法的修饰符。

类中的static静态变量:

static变量实际上属于类(并不属于某一个对象),所以自然这些static变量也属于“类的相关信息”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: