`
龙飞凤舞的程序员
  • 浏览: 1188 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

Java虚拟机内存管理

 
阅读更多
最近在看JVM的书籍,为加深自己的印象,打算边看边记录自己看后的总结。欢迎大家给出意见

平常我们都把Java虚拟机的内存分为‘栈内存’和‘堆内存’,其实,这是很粗略的,因为Java虚拟机的内存管理,
远远比这个要复杂的多。
Java虚拟机的内存管理,大致可分为5部分:

1、程序计数器
2、虚拟机栈
3、本地方法栈
4、堆
5、方法区

以上5个部分中,虚拟机栈就是我们程序员平常所说的栈内存,堆就是我怕们程序员平常所说的堆内存。

1、程序计数器:
顾名思义,它的作用就是告诉虚拟机,应该执行程序中哪一行代码。它占用一块较小的内存区域,是当前线程所致行的字字节码的行号指示器。
大家都知道,java代码需要编译成二进制class字节码文件才能在Java虚拟机中执行,执行在Java虚拟机中,执行calss文件的部分叫做字节码解释器,而字节码工作时,就是通过改变这个程序计数器的值,來选取下一条需要执行的字节指令。
Java虚拟机的多线程是通过线程轮流切换分配处理器执行时间的方式。故,为了保证各个线程之间的计数器互不影响,每个线程都有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,这块内存区域,我们称之为‘线程私有’的内存。
如果线程执行的是一个Java方法,这个计数器记录的就是正在执行的虚拟机字节码指令的地址。
如果线程执行的是一个Native方法(本地方法,即JNI技术,指Java直接调用其他语言代码(如C语言)进行交互),这个计数器值则为空(Undefined),此区域是唯一一个在Java虚拟机规范中,没有规定任何OutOfMemoryError情况的区域。

2、虚拟机栈
它也是线程私有的。它有若干个栈帧组成,栈帧,是在每个方法被执行所创建,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法被调用,到执行完成的过程,就对应着一个栈帧在虚拟机栈中,从入栈到出栈的过程。
局部变量表:我们所说的栈内存,具体点,就是指虚拟机栈中的局部变量表。
局部变量表存放了在编译期可知的各种基本数据类型、对象引用和returnAddress类型(指向一条字节码指令的地址)。其中,64为长度的long和double类型,会占用两个局部变量空间(Slot),其余都只占用一个。局部变量表所需要的内存空间,都是在编译期间完成分配,在运行期间,不会改变局部变量表的大小。
此区域的两种异常:
* 线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError
* 虚拟机栈动态扩展时,超过Java虚拟机规范允许的固定大小,抛出OutOfMemoryError

3、本地方法栈
与虚拟机栈类似,区别是本地方法栈是为虚拟机使用Native方法服务的。

4、堆
Java堆,是Java虚拟机内存中最大的一块。共享于所有线程。它用于存放对象的实例,差不多所有的对象实例,都在这里分配。Java堆可以处在物理不连续的内存空间中,但逻辑上要连续。
如果堆中没有内存完成实例分配时,将会抛出OutOfMemoryError

5、方法区
与Java堆类似,也是各个线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译的代码等数据。它有个别名:Non-Heap(非堆),目的为了与堆区分开。
对此区域,可以选择不实现垃圾回收。相对与堆,在这个区域,发生垃圾回收的行为是比较少见。这个区域回收的目标,主要针对常量池回收和类型卸载。
运行常量池:方法区的一部分。Class文件中,除了有类的版本、字段、方法、接口等描述信息外,还有一项,就是常量池,用于存放编译期生成的各种字面量和符号引用。这部分在类加载器加载后,存放在方法区的运行常量池中。
运行常量池具备动态性,就是说在运行期间,也可以将新的常量放入池中,如String类的intern()方法。同样,它也有OutOfMemoryError异常。

进一步理解
如下面这条语句

Object obj = new Object();

Object obj将会反映到虚拟机栈中(reference类型)
new Object()将会反映到Java堆中
此类的对象类型、父类、实现的接口、方法等信息数据,将反映到方法区中

如果是下面的语句呢?

int i = 1;

这个就留给各位看官自己思考吧,呵呵!



































分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics