浅入理解JVM

JVM全称java虚拟机。HelloWorld.java(源代码) ->Hello.class->010101(2进制编码),class文件和2进制编码需要在JVM中运行。

运行时的数据区:

蓝色的是数据区,绿色的是指令区。

程序计数器:一块较小的内存空间,指向当前线程所执行的字节码指令的地址和行号,每条线程都有一个独立的程序计数器。唯一不会OOM的区域。

虚拟机栈:线程私有,存储当前运行方法所需要的数据、指令、返回地址。

每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接(比如存储的一个接口,运行时会解析找到实现类)、方法出口等信息。一个方法对应一个栈帧。局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度long 和 double占两个局部变量空间,其他只占一个。可能出现2种异常:1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;2.如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就抛出OutOfMemoryError异常。设置JVM参数”-Xss228k”(即栈大小为228k)。

 本地方法栈:和Java虚拟机栈很类似,不同的是本地方法栈为Native方法服务。

在HotSpot虚拟机实现中是把本地方法栈和虚拟机栈合二为一的。同理也会抛出StackOverflowError和OutOfMemoryError。

Java堆:是Java虚拟机所管理的内存中最大的一块。由所有线程共享,在虚拟机启动时创建。堆区唯一目的就是存放对象实例。堆中可细分为新生代和老年代,新生代又可分为Eden空间、From Survivor空间、To Survivor空间。堆无法扩展时,抛出OutOfMemoryError异常。设置JVM参数” -Xms20M -Xmx20M“(前者表示初始堆大小20M,后者表示最大堆大小20M)。

方法区:所有线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。当方法区无法满足内存分配需求时,抛出OutOfMemoryError。

另外一个说法——永久代(Permanent Generation),呼应堆的新生代和老年代。方法区和堆的划分是JVM规范的定义,而不同虚拟机有不同实现,对于Hotspot虚拟机来说,将方法区纳入GC管理范围,这样就不必单独管理方法区的内存,所以就有了”永久代“这么一说。设置JVM参数为”-XX:MaxPermSize=20M”(方法区最大内存为20M)。JDK7后则将字符串常量池移到了Java堆中,至于JDK8则是纯粹取消了方法区这个概念,取而代之的是”元空间(Metaspace)“,所以在JDK8中虚拟机参数”-XX:MaxPermSize”也就没有了任何意义,取代它的是”-XX:MetaspaceSize“和”-XX:MaxMetaspaceSize”等。

直接内存:并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。JDK1.4加入了NIO,引入一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。因为避免了在Java堆和Native堆中来回复制数据,提高了性能。当各个内存区域总和大于物理内存限制,抛出OutOfMemoryError异常。

未完待续。。。。

猜你喜欢

转载自www.cnblogs.com/dream2true/p/10828769.html