深入理解JVM

   Java程序通过编译生成class文件,生成的class文件通过JVM(Java Virtual Machine)来运行,JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,Java虚拟机所管理的内存将会包括以下几个运行时数据区域

 

程序计数器(Program Counter Register)

       学过《计算机组成原理》的人对于这个名词都不会感到陌生,PC指向当前执行的指令地址。在JVM中,也可以这么理解,根据PC值选取将要执行的指令。JVM的多线程是通过线程轮流切换并根据CPU时间分片的方式来实现,任何时刻,一个处理器只会执行一条线程中的指令。每条线程都需要有一个独立的程序计数器各条线程之间的计数器互不影响,独立存储,这类内存区域为“线程私有”的内存。Java中有两种方法:Java方法和本地方法。如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的指令地址;如果正在执行的是Natvie 方法,这个计数器值为空(Undefined)

本地方法栈(Native Method Stack)

       Java本地方法(Native Method)是由其它语言编写的编译成和处理器相关的机器代码,保存在动态链接库中,即.dll(windows系统)文件中,格式是各个平台专有的。虽说Java方法是与平台无关的,但是本地方法不是。程序运行中Java方法调用本地方法时,JVM装载包含这个本地方法的动态库的,并调用这个方法。通过本地方法,Java程序可以直接访问底层操作系统的资源,如果你这样用,你的程序就变成平台相关了,因为本地方法的动态库是与平台相关的,但是使用本地方法还可能把程序变得和特定的Java平台实现相关。
        本地方法栈与虚拟机栈(后面介绍)作用类似,Sun HotSpot中直接将本地方法栈和虚拟机栈合二为一,它和虚拟机栈一样都会抛出StackOverflowError和OutOfMemoryError异常。

 

方法区(Method Area)

      方法区是各个内存所共享的内存空间 方法区中主要存放被JVM加载的类信息、常量、静态变量、即时编译后的代码等数据。常把方法区成为永久代(听说不严谨),方法区的大小用户可以更改,如果发生溢出会出现java.lang.OutOfMemoryError:PermGen space信息。

运行时常量

      运行时常量是方法区的一部分。Class文件有一个常量池用来存放编译器生成的各种字面量和符号引用,这部分内容在类加载后存放到方法区的运行时常量池中。
      运行时常量池相对于Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。

 

虚拟机栈(VM Stack)

       从图中可以看出,JVM的栈中存放的数据主要有:
1.各种基础数据类型(boolean、byte、char 、short、int、float、long、double );
2.方法的形式参数,方法调用完后从栈空间回收;
3.引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC。
       JVM的栈也属于线程私有的内存,用户可以设置大小,后面会讲到。对于异常,这块区域有两种情况:如果线程请求的栈深度大于JVM所允许的深度,将抛出StackOverflowError异常;如果JVM的栈可以动态扩展,但是在尝试扩展时无法申请到足够的内存则抛出OutOfMemoryError异常。

 

堆(Heap)

      Java 堆是JVM所管理的内存中最大的一块并且是所有线程共享的内存区域,在JVM启动时创建。堆存放的就是存放对象实例和数组,几乎所有的对象实例都在这里分配内存。Java堆是垃圾回收器管理的主要区域,后面将详细介绍。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。

 

直接内存

       直接内存并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现。
         为了提高IO速度,在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据。显然,本机直接内存的分配不会受到Java 堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM 及SWAP 区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值