文章主要是阅读《深入理解java虚拟机:JVM高级特性与最佳实践》第二章:Java内存区域与内存溢出异常

的一些笔记以及概括。

好了開始。假设有什么错误或者遗漏,欢迎指出。

一、概述

先上一张图

这张图主要列出了Java虚拟机管理的内存的几个区域。

常有人把Java内存区分为堆内存(Heap)和栈内存(Stack)。这样的分法比較粗糙,Java内存区域的划分实际上远比这复杂。从上图就能够看出了。

堆栈分法中所指的“栈”实际上仅仅是虚拟机栈,或者说是虚拟机栈中的局部变量表部分。

接下来主要解说区域的各个部分.

二、执行时数据区域

1.程序计数器

  • .程序计数器(Program Counter Register)是一块较小的内存空间,它的作用能够看做是当前线程所运行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型。各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条须要运行的字节码指令
  • Java虚拟机的多线程是通过线程轮流切换并分配处理器运行时间的方式来实现的,在不论什么一个确定的时刻。一个处理器(对于多核处理器来说是一个内核)仅仅会运行一条线程中的指令。

    因此。为了线程切换后能恢复到正确的运行位置。每条线程都须要有一个独立的程序计数器。各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

  • 线程正在运行的是一个Java方法,假设正在运行的是Natvie方法。这个计数器值则为空(Undefined)。

    此内存区域是唯一一个在Java虚拟机规范中没有规定不论什么OutOfMemoryError情况的区域。

2.Java虚拟机栈

栈帧是方法执行期的基础数据结构栈容量可由-Xss參数设定

  • 与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程同样。

    每个方法被调用直至运行完毕的过程。就相应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

  • 常有人把Java内存区分为堆内存(Heap)和栈内存(Stack),这样的分法比較粗糙,Java内存区域的划分实际上远比这复杂。

    当中所指的“堆”在后面会专门讲述,而所指的“栈”就是如今讲的虚拟机栈。或者说是虚拟机栈中的局部变量表部分。

  • 局部变量表所需的内存空间在编译期间完毕分配,当进入一个方法时。这种方法须要在帧中分配多大的局部变量空间是全然确定的,在方法执行期间不会改变局部变量表的大小。

    主要存放了编译期可知的各种基本数据类型、对象引用(reference类型)、returnAddress类型

3.本地方法栈

栈容量可由-Xss參数设定

虚拟机栈为虚拟机运行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

4.Java堆

可通过參数 -Xms 和-Xmx设置  。

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被全部线程共享的一块内存区域。在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,差点儿全部的对象实例都在这里分配内存。

5.方法区

參数-XX:MaxPermSize可设置 .

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机载入的类信息、常量、静态变量、即时编译器编译后的代码等数据。尽管Java虚拟机规范把方法区描写叙述为堆的一个逻辑部分。可是它却有一个别名叫做Non-Heap(非堆)。目的应该是与Java堆区分开来。

6.执行时常量池

能够通过-XX:PermSize和-XX:MaxPermSize设置

  • 执行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件里除了有类的版本号、字段、方法、接口等描写叙述等信息外,另一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用。这部分内容将在类载入后存放到方法区的执行时常量池中。
  • 执行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定仅仅能在编译期产生。执行期间也可能将新的常量放入池中,这样的特性被开发者利用得比較多的便是String类的intern()方法。

7.直接内存

可通过-XX:MaxDirectMemorySize指定。假设不指定,则默认与Java堆的最大值(-Xmx指定)一样

直接内存(Direct Memory)并非虚拟机执行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,可是这部分内存也被频繁地使用。并且也可能导致OutOfMemoryError异常出现

三、HotSpot虚拟机对象探秘

主要探讨HotSpot虚拟机在Java堆中对象分配、布局和訪问的全过程。

1.对象的创建

虚拟机遇到new指令时。

  • 首先去检查这个指令的參数是否能在常量池中定位到一个类的符号引用。而且检查引用代表的类是否已被载入、解析和初始化过。假设没有,则运行类载入过程(第7章)。
  • 载入检查通过后。分配内存(内存在类载入完毕后便可全然确定)。
  • 内存分配完毕后,虚拟机对对象进行必要的设置。如对象是哪个类的实例、怎样找到类的元数据信息等(都放在对象的对象头中)。

  • 从虚拟机角度看,一个新的对象产生了。但从java程序视角看,对象创建才刚刚開始,由于<init>方法还没有运行。,全部字段为零。运行new指令之后会接着运行<init>方法(构造方法),进行初始化,这样一个真正可用的对象才算完毕产生。

2.对象的内存布局

分为对象头、实例数据、对齐填充三部分。

1)对象头

包括两部分

  • 存储对象自身的执行时数据,如哈希码、GC分代年龄等。

    长度在32位和64位的虚拟机中。分别为32bit、 64bit,官方称它为“Mark Word”

  • 类型指针,对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

注:假设对象是一个java数组。对象头中还必须有一块记录数据长度的数据。

2)实例数据

对象真正存储的实用信息,也是程序中定义的各种类型的字段内容。

3)对齐填充

因为HotSpot虚拟机要求对象的起始地址必须是8字节的整数倍。通俗的说,就是对象大小必须是8字节的整数倍。

对象头正好是8字节的倍数。当实例数据部分没有对齐时,须要通过对齐填充来补全。

3.对象的訪问定位

对象訪问在Java语言中无处不在,是最普通的程序行为。但即使是最简单的訪问。也会却涉及Java栈、Java堆、方法区这三个最重要内存区域之间的关联关系,如以下的这句代码:

   Object obj = new Object();

 如果这句代码出如今方法体中。那“Object obj”这部分的语义将会反映到Java栈的本地变量表中,作为一个reference类型数据出现。

而“new Object()”这部分的语义将会反映到Java堆中。形成一块存储了Object类型全部实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存

因为reference类型在Java虚拟机规范里面仅仅规定了一个指向对象的引用,并未定义这个引用应该通过哪种方式去定位。以及訪问到Java堆中的对象的详细位置,因此不同虚拟机实现的对象訪问方式会有所不同,主流的訪问方式有两种:使用句柄和直接指针。

四、总结

最后上一张本章结构图:

深入理解java虚拟机系列(一):java内存区域与内存溢出异常的更多相关文章

  1. 【java虚拟机系列】java虚拟机系列之JVM总述

    我们知道java之所以能够快速崛起一个重要的原因就是其跨平台性,而跨平台就是通过java虚拟机来完成的,java虚拟机属于java底层的知识范畴,即使你不了解也不会影响绝大部分人从事的java应用层的 ...

  2. 【java虚拟机系列】java中类与对象的加载顺序

    首先了解一下Java虚拟机初始化的原理. JVM通过加装.连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用.类型的生命周期如下图所示: 装载和连接必须在初始化之前就要完成. 类 ...

  3. 【java虚拟机系列】从java虚拟机字节码执行引擎的执行过程来彻底理解java的多态性

    我们知道面向对象语言的三大特点之一就是多态性,而java作为一种面向对象的语言,自然也满足多态性,我们也知道java中的多态包括重载与重写,我们也知道在C++中动态多态是通过虚函数来实现的,而虚函数是 ...

  4. 【java虚拟机序列】java中的垃圾回收与内存分配策略

    在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...

  5. 《深入理解Java虚拟机》-----第2章 Java内存区域与内存溢出异常

    2.1 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任 ...

  6. 《深入理解 Java 虚拟机》读书笔记:Java 内存区域与内存溢出异常

    前言 最近开始看这本书,记得前段时间拿起这本书的时候,心情是相当沉重的!当时的剧本是这样的-- 内景.家里 - 下午 我(画外):唉,有点无聊啊!(偶然撇过书架)这么多书得看到什么时候啊,要不要拿一本 ...

  7. 《深入理解 Java 虚拟机》学习 -- Java 内存模型

    <深入理解 Java 虚拟机>学习 -- Java 内存模型 1. 区别 这里要和 JVM 内存模型区分开来: JVM 内存模型是指 JVM 内存分区 Java 内存模型(JMM)是指一种 ...

  8. Java虚拟机系列(一)---Java内存划分

    Java和C++之间有一堵由内存管理和垃圾收集技术所围成的“高墙”,墙外的人想进去,墙内的人却想出来.  ------摘自<深入理解Java虚拟机> 作为一个Java程序员,因为虚拟机的好 ...

  9. Java内存区域与内存溢出异常——深入理解Java虚拟机 笔记一

    Java内存区域 对比与C和C++,Java程序员不需要时时刻刻在意对象的创建和删除过程造成的内存溢出.内存泄露等问题,Java虚拟机很好地帮助我们解决了内存管理的问题,但深入理解Java内存区域,有 ...

随机推荐

  1. haproxy redirect location和redirect prefix

    <pre name="code" class="html">redirect location <loc> [code <code ...

  2. Mfc资源消息的响应机制

    Mfc消息的响应机制 Mfc中有很多资源,如图标资源,菜单资源,工具栏资源等等:那么,资源是如何进行消息响应和消息映射的呢? 它们的流程是: 某种资源——对应的ID号——消息映射——响应函数的声明与实 ...

  3. Ext JS4百强应用:设置textfield的悬浮提示信息 --第8强

    在Extjs4中有时候我们需要textfield的提示信息,但是我们发现textfield并没有这样的配置项. 这时候我们就要另想方法:我们需要在鼠标悬停在textfield组件的时候进行信息的提示, ...

  4. ios添加pre和post build action

    再vs中,我们可以很方便的再build前.后执行一些脚本为我们做点什么事情.再ios中怎么搞呢,哪必然是对xcode进行操作了.再google搜索了一把,有说操作Scheme的也有说再直接再targe ...

  5. [Android学习笔记]Android向下兼

    Android向下兼容的思路:使用高版本的API,在运行时判断真实运行平台的API版本,根据不同版本做不同的处理 关键类:Build.class里面定义了API版本相关信息 内部类:VERSION定义 ...

  6. MPICH3环境配置

    最新版的mpich简化了运行方式,不再提供mpd开头的命令,只需要一个mpiexec即可启动mpi运行环境,方便了mpi编程.源代码下载地址:http://www.mpich.org/download ...

  7. Contact类解析

    Contact类 public static class Contacts implements BaseColumns, ContactsColumns, ContactOptionsColumns ...

  8. 11 款最好 CSS 框架 让你的网站独领风骚

    网页设计和发展领域已经成为竞争激烈的虚拟世界.想要在网络的虚拟世界中生存,仅有一堆静止的在线网络应用是远远不够的,网页必须要有很多功能,配以让人无法抗拒的设计.网页编码一定要合适.精确,才能保证不发生 ...

  9. hadoop源码下载地址

    http://svn.apache.org/repos/asf/hadoop/common/branches/

  10. vs2008编译QT开源项目--太阳神三国杀源码分析(三) 皮肤

    太阳神三国杀的界面很绚丽,界面上按钮的图标,鼠标移入移出时图标的变化,日志和聊天Widget的边框和半透明等效果,既可以通过代码来控制,也可以使用皮肤文件qss进行控制.下面我们分析一下三国杀的qss ...