您的位置:首页 > 编程语言 > Java开发

Java内存区域划分及对象的访问方式

2018-01-06 02:09 459 查看

JVM 内存区域划分

JVM 内存区域划分如图:



下面对以上划分具体讲解:

程序计数器

程序计数器用来指示当前字节码执行到第几行。每个计数器只能记录一个线程的行号,所以他是线程私有的。

当程序执行Java方法时,其记录当前执行指令地址;

当执行本地(native,使用c语言编译)方法时,其值为 Undefined

由于其单一功能,它是唯一一个没有内存溢出(OutOfMemoryError)的区域.

虚拟机栈

一个线程的每一个方法在执行的同时,都会在虚拟机栈创建对应的栈帧。方法的调用和完成对应着栈帧在虚拟机栈中的入栈与出栈。

   栈帧 :栈帧中存储方法的局部变量表,操作站,动态链接,方发出口等内容。

   局部变量表 :存放方法的局部变量(基本数据类型,对象的引用
reference
,返回地址等)

其中只有
long
double
占用两个局部变量空间(slot),其他都是一个局部变量空间。

局部变量表在编译时就已经确定,方法运行所需要分配的空间在栈帧中完全确定,在方法的整个生命周期都不会发生改变。

   局部变量空间
slot
:对于32位机器,1 slot = 32 bit

   异常:当请求栈深度大于JVM允许栈深度时,抛出
StackOverFlowError
(栈溢出)异常;由于栈深度可动态改变,直至内存不足时会抛出
OutOfMemoryError
(内存溢出)异常

  每个线程都对应一个虚拟机栈,因此也是线程私有的。

本地方法栈

   同上,唯一区别是本地方法栈执行
native
方法。

堆区(Heap)

   是JVM中最重要最大的区域。所有线程共享。用来存储对象实例。会抛出
OutOfMemoryError:Iava heap space
(内存溢出)异常

方法区(Method Area)

   方法区在JDK1.6版本HotSpot虚拟机中被设计为永久代,可能会在后续设计中取消。

   方法区用来存储虚拟机加载的类信息(版本,field,方法,接口等),静态变量,编译器即时编译代码等。

   对方法区的垃圾回收操作主要集中在对常量池的内存回收以及对已加载类的卸载。

   会抛出
OutOfMemoryError:PermGen space
(内存溢出)异常

运行时常量池(Runtime Constant Pool)

   1. 存储编译期就生成的字面常量,符号引用,翻译后的直接引用。

      符号引用:编码是用字符串表示某个变量,接口的位置等

      直接引用:经过翻译的地址。在类链接阶段完成翻译

   2. 存储运行时产生的常量,比如
String.intern()
方法,该方法判断常量池中有没有已存在的字符串常量,没有则新建,有则返回地址。

直接内存

   JDK基于通道(Channel)和缓冲区(Buffer)的内存分配方式。假设机器有4G内存,1G被JVM占用,则剩余3G为直接内存。

JVM中对象访问方式

   以
Object obj = new Object()
为例:Object obj 作为一个本地引用(reference)存储在虚拟机栈中的本地变量表中。

   new Object() 作为对象实例存储在堆中。Object类的类型信息数据存储在方法区中。

   常见的对象访问有两种:

   1. 句柄访问

      如下图所示:

      


   在这种访问方式中,JVM堆中会有专门的一块区域作为句柄池。这种方法的优点是稳定

   2. 直接指针访问

      如下图所示:

      


   此种方式中,JVM堆中存储的对象信息包含了在方法区中相应的类型数据地址。其优势在于速度快。而在HotSpot虚拟机中就用的这种方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java jvm