文章主要是阅读《深入理解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. 基于visual Studio2013解决面试题之0205查找路径

     题目

  2. 显示器 Linux 性能 18 (一个命令行工具传递)

    对于系统和网络管理员来说每天监控和调试Linux系统的性能问题是一项繁重的工作.在IT领域作为一名Linux系统的管理员工作5年后,我逐渐认识到监控和保持系统启动并执行是多么的不easy.基于此原因. ...

  3. Swift - 点击输入框外部屏幕关闭虚拟键盘

    我们如果把文本框的Return Key设置成Done,然后在storyboard中将文本框的Did End On Exit事件在代码里进行关联.同时关联代码里调用文本框的resignFirstResp ...

  4. linux c正则

    c 正则 --------------------------------------------------    标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一 ...

  5. 基于raw os 的事件触发系统

    Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...

  6. 【m从翻译os文章】写日志禁令Sqlnet.log和Listener.log

    写日志禁令Sqlnet.log和Listener.log 参考原始: How to Disable Logging to the Sqlnet.log and the Listener.log (Do ...

  7. Mysql免安装版脚本

    使用Mysql过程中经常需要使用到免安装版本(绿色版)的Mysql,开始网上搜了一大堆,但还真是不怎么好用. 只好自己琢磨了一番,现在放出来和大家分享下: //安装启动服务 @ECHO OFF if  ...

  8. WPF入门介绍

    Windows Vista已经于2007年1月30正式发行零售版本,安装Vista的计算机将会大量出现.在Vista时代,身为编程员,就一定要具备Vista桌面应用开发的能力.而开发Vista桌面应用 ...

  9. 如何在Android Studio上使用Github

    首先,登陆到Github上并创建一个新repository.在屏幕右上角,点击“+”标记,并且选择“New repository”. 现在完成这个表格以新建一个叫做testproject的新repos ...

  10. JAVA NIO 选择器

    为什么要使用选择器 通道处于就绪状态后,就可以在缓冲区之间传送数据.可以采用非阻塞模式来检查通道是否就绪,但非阻塞模式还会做别的任务,当有多个通道同时存在时,很难将检查通道是否就绪与其他任务剥离开来, ...