深入JAVA虚拟机之运行时数据区

前言
最近在啃一本书《深入JAVA虚拟机》,这本书不是第一次看,可以说是从大学就开始看,
这一次应该算第三次啃这本书,也应该说算是第一次真正啃这本书。大学的时候,只是好奇表层的一些神奇现象,随着工作几年后,现在回过头来再次啃这本书,对于表层的那些以前觉得神奇的现在已经感觉乏味,反而对于底层是如何实现、如何运作的越来越着迷。这也是这次看这本书的初衷。通过写博客记录下自己的学习过程,也方便以后回头看看现在的看法想法在将来会变成怎样。如果我在下面的文字表述上或者理解上有误解或者错误,请各位大神能够留言指正,如果有跟我一样爱好的同学,也欢迎留言探讨,相互学习。



概述

       对于c/c++开发者而言,他们对内存管理拥有最高权利,但是需要干最多“活”的劳动
人民。他们担负者每一个对象生命周期从开始到结束的责任(需要分配内存,回收内存)。
对于java开发者而言,这些苦逼的活不需要做,因为都交给JVM的**自动内存管理机制**
去做了。有句调侃的话叫:人生苦短,我用XXXX.那么java开发者真就轻松了吗?
不!虽然把内存管理交给JVM去做了,但要是程序一旦出先内存泄漏、内存溢出等问题,
如果不清楚虚拟机是如何使用内存的,那么排除错误将会比他们更加苦逼。

运行时数据区

java虚拟机在执行程序过程中,会把**管理的内存**,划分为多个**数据区**。它们都有特
定的用途。包括:方法区,堆,程序计数器,虚拟机栈,本地方法栈,运行时常量池,直
接内存

1.程序计数器

它是一块很小的内存。作用可看作是:当前线程所执行的字节码的行号指示器。字节码解
释器就是通过它获取一条需要执行的字节码指令。java虚拟机多线程是通过线程轮流切换
并分配处理器时间来实现的,在确定的时间一个处理器,只会执行一条指令。所以为了线
程在切换时能够回到在正确的位置,每一个线程都有独立的程序计数器,是当前线程私有
的。各个线程之间的计数器是互不影响,独立存储的,称之为线程私有的内存区域。
    特点:
        线程间互不影响,独立存储。

2.虚拟机栈

它也是线程私有的,生命周期与线程相同,是java方法执行时的内存模型。每个方法执
行时,都会创建一个栈幀,用于存储局部变量表、操作栈、动态链接、方法出口等信息。
局部变量表存放了编译期可知的基本数据类型,对象引用和return Address类型。

3.本地方法栈

为虚拟机使用native方法服务。它的作用和虚拟机栈非常相似,不同点就是服务的对象
不同,前者是给java方法服务,而后者是给native方法服务。

4.java堆

是java虚拟机中管理最大的一块内存区域。是被所有线程所共享的内存区域。在虚拟机
启动时创建,唯一目的就是存储对象实例。是java垃圾收集器的主要管理区域,这里又
被成为GC堆。从内存回收来看,现在的垃圾收集器实现大都是使用分代收集算法,
所以java堆还可以细分为:新生代,老年代,再细分为:eden空间,from servivor空间,
To Servivor空间。该片内存,可以在物理上不是连续的,只要逻辑上连续即可。
可动态扩展的(-Xms,-Xmx)。

5.方法区

所有线程共享,用于存储虚拟机加载的类信息、常量、静态变量、即使编译的代码等数据。

运行时常量池
是方法区的一部分。class文件内除了有类的版本信息、字段、方法、接口等描述信息外,
还有一项常量池。这个常量池用于存放编译期生成的各种字面量和符号引用,在类加载后
存放到方法区。

6.直接内存

并不是运行时数据区内存中的一部分,也不是虚拟机规范定义的内存,因为频繁使用,也
可能出现OutOfMemoryError异常。在jdk1.4加入的NIO类,引入了一种基于通道/缓冲区
的I/O方式,它可以使用native函数库直接分配堆外内存,通过存储在java堆中
的DirectByteBuffer对象作为这块内存的引用进行操作。

图示:

总结:
    1.程序计数器,是线程私有的,线程间相互独立,是唯一一个不会抛出OutOfMemoryError异常的运行时数据区。
    2.虚拟机栈,是线程私有的,与线程生命周期相同,是方法执行时的内存模型,通常说的栈内存指的就是这个
    虚拟机栈。
    3.本地方法栈,与虚拟机栈非常相似,服务对象不同,一个是服务Native方法,一个是服务Java方法。
    4.Java堆,最大的一块内存,线程共享区,虚拟机启动时创建,垃圾收集器的主要用武之地,所以这里又叫
    GC堆。可动态扩展。
    5.方法区,所有线程共享,记录虚拟机加载的类信息,常量、静态变量、即时编译的代码。


现在也已经清楚了运行时数据区的职责划分,那么现在可以开始讨论java是如何访问对象的。

  • 对象访问

java中对象访问随处可见,那么你知道它是怎么实现访问对象的吗?在java中就算最简单的对象访问都必然会
涉及到java栈、java堆、方法区这三个最重要的内存区域。举例如下:

Object obj = new Object();

假设上面语句出现在一个方法体内,Object obj会被反映到java栈,作为一个reference类型数据出现。
而new Object()会反映到java堆中,在java堆中,开辟出一块存储object类型实例数据值的结构化内存,java堆中
还必须要保存对象类型数据的地址信息,而对象类型数据就保存在方法区内。

但是因为reference类型在java虚拟机规范中说指向一个对象的引用,并没有说明该引用通过什么方式去定位和如何访问java堆中的对象具体位置。根据不同的虚拟机实现,会有不同的方式,主流的方式就两种:句柄、直接指针
下面是两种方式的示意图:


原文地址:http://blog.51cto.com/4837471/2157417

时间: 2024-10-08 13:51:04

深入JAVA虚拟机之运行时数据区的相关文章

深入理解Java虚拟机:运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁.根据<Java虚拟机规范(Java SE 7版)>的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域. 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里

Java虚拟机运行时数据区

PS:时间一晃好久了,距离上一篇文章过去许久了,出自两个方面的原因,其一,公司的项目接近尾声,用户提出的需求功能需要马上的解决:其二,出自整天加速完善和修改需求功能,下班之后几乎不想再继续下去了,懒散情绪有了. 扯淡话题结束了,开始继续学习笔记文章的整理,每天一小步,久而久之就是巨大的一步.今天要扯的话题是Java虚拟机的运行时数据区. Java虚拟机(JVM)是 由JDK提供的一个软件程序,而其任务就是执行Java程序,下面给出虚拟机执行Java的过程图. 从图中可以看出由Java源文件编译出

深入理解Java运行时数据区

前情回顾 在本专栏的前12篇博客中, 我们主要大致介绍了什么是JVM, 并且详细介绍了class文件的格式. 对于深入理解Java, 或者深入理解运行于JVM上的其他语言, 深入理解class文件格式都是必须的. 如果读者对class文件的格式不是很熟悉, 在阅读本博客下面的文章之前, 建议先读一下前面的12篇博客, 或者参考其他资料, 熟悉class文件的格式. 在深入理解Java虚拟机到底是什么 这篇博客中, 我们有提到过, JVM就是一个特殊的进程, 我们执行的java程序, 都运行在一个

Java虚拟机 运行时数据区

Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随线程的开始和结束而创建和销毁. Java虚拟机所管理的内存将会包括以下几个运行时数据区域 程序计数器(Program Counter Register) 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器. 每一条JVM线程都有自己的PC寄存器,各条线程之间互不影响,独立存

Java 虚拟机运行时数据区介绍

引言 Java 虚拟机(Virtual Machine)在执行 Java 程序时, 会将它所管理的内存划分为不同的数据区,这些分块有不同的功能,理解它们各自的特点,对于深入理解java程序运行机制和调优Java代码,具有重要意义.其实个人觉得,理解 Java 虚拟机的原理,也没想象中的复杂(也许我的想法有点天真啊^_^),它的运行机制,就像一个小型操作系统,这也许就是虚拟机的来源吧. Java VM运行时数据区结构图 运行时数据区域解释 本地方法栈 该区域所发挥的作用与虚拟机栈类似,只不过它是为

《深入理解Java虚拟机》笔记01 -- 运行时数据区

运行时数据区示意图 1. 程序计数器 占用一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.主要用来记录线程执行到哪条语句了,分支.循环.跳转.异常处理.线程恢复等功能都需要依赖这个计数器来完成. 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址:如果正在执行的时Native方法,这个计数器值则为空.此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域. 2. Java 虚拟机栈 线程私有,生命

【Java虚拟机结构(第2部分)运行时数据区】摘要

<Java虚拟机规范(Java SE 7版)>作者:Tim Lindholm.Frank Yellin.Gilad Bracha.Alex Buckley 摘要:第二章 Java虚拟机结构(第2部分) 本规范描述的是一种抽象化的虚拟机的行为,而不是任何一种被广泛使用的虚拟机实现. 2.5 运行时数据区 Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁.另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程开始和结束而

Java虚拟机运行时数据区结构

本文部分参考自<Java虚拟机规范(Java SE 7版)>的中译本和周志明的<深入理解Java虚拟机>,另加个人理解.原书对Java虚拟机运行时数据区描述只有6页,同时参考其他网络网资料,个人能力所限,不排除存在认知错误. JVM将程序运行期间使用的内存划分为若干个运行时数据区,其中一些会随着虚拟机启动而创建,随着虚拟机退出而销毁.另外一些与线程一一对应,随着线程开始而创建,随着线程结束而销毁.数据区划分如下图所示意: Java堆(Java Heap) 在JVM中,Java堆是可

《Java虚拟机规范》阅读笔记-运行时数据区

Java虚拟机运行时数据区包括PC寄存器.Java虚拟机栈.Java堆.方法区.本地方法栈.运行时常量池六个部分. 1. PC寄存器 PC寄存器(又叫程序计数器,Program Counter Register),每一条Java虚拟机线程都有自己的PC寄存器.PC寄存器报错当前正在执行方法的字节码指令地址:如果当前方法是native的,则PC寄存器的值为undefined. 2. Java虚拟机栈 Java虚拟机栈(Java Virtual Machine Stack),每一条Java虚拟机线程