1、Java内存区域与内存溢出异常(JVM笔记)

2017-03-10  本文已影响81人  yjaal

声明:本文集中的文章都是看了《深入理解Java虚拟机》所做的笔记,很多内容是从书中摘抄,特此声明。这里主要学习一些基本的概念,真正掌握可能还需要多加实践。

一、运行时数据区域

注:图片来自http://www.jianshu.com/p/6173a467165e

1
Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域,根据《Java虚拟机规范(Java SE 7版)》的规定,Java虚拟机所管理的内存将会包含如图所示的几个运行时区域。

1.1 程序计数器

程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。此内存区域是惟一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

1.2 Java虚拟机栈

1.3 本地方法栈

本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法中方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(如Sun HotSpot)直接就把本地方法栈和虚拟机栈合二为一。

1.4 Java堆

1.5 方法区

1.6 运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant poo Table),用于存放编译器期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

1.7 直接内存

二、HotSpot虚拟机对象探秘

2.1 对象的创建

在语言层面上,创建对象通常仅仅是一个new关键字而已,现在看在虚拟机中是怎样的过程。

2.2 对象的内存布局

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头包括两部分信息:

存储内容 标志位 状态
对象哈希码、对象的分代年龄 01 未锁定
指向锁记录的指针 00 轻量级锁定
指向重量级锁的指针 10 膨胀(重量级锁定)
空,不需要记录信息 11 GC标记
偏向线程ID、偏向时间戳、对象分代年龄 01 可偏向

2.3 对象的访问定位

建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种。

这两种对象访问方式各有优势,使用句柄来访问最大的好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。使用直接指针访问方式最大的好处就是速度更快。对于Sun HotSpot而言,使用的是第二种方式进行对象访问的。

上一篇 下一篇

猜你喜欢

热点阅读