深入理解java虚拟机系列(一):java内存区域与内存溢出异常
文章主要是阅读《深入理解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内存区域与内存溢出异常的更多相关文章
- 【java虚拟机系列】java虚拟机系列之JVM总述
我们知道java之所以能够快速崛起一个重要的原因就是其跨平台性,而跨平台就是通过java虚拟机来完成的,java虚拟机属于java底层的知识范畴,即使你不了解也不会影响绝大部分人从事的java应用层的 ...
- 【java虚拟机系列】java中类与对象的加载顺序
首先了解一下Java虚拟机初始化的原理. JVM通过加装.连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用.类型的生命周期如下图所示: 装载和连接必须在初始化之前就要完成. 类 ...
- 【java虚拟机系列】从java虚拟机字节码执行引擎的执行过程来彻底理解java的多态性
我们知道面向对象语言的三大特点之一就是多态性,而java作为一种面向对象的语言,自然也满足多态性,我们也知道java中的多态包括重载与重写,我们也知道在C++中动态多态是通过虚函数来实现的,而虚函数是 ...
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...
- 《深入理解Java虚拟机》-----第2章 Java内存区域与内存溢出异常
2.1 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任 ...
- 《深入理解 Java 虚拟机》读书笔记:Java 内存区域与内存溢出异常
前言 最近开始看这本书,记得前段时间拿起这本书的时候,心情是相当沉重的!当时的剧本是这样的-- 内景.家里 - 下午 我(画外):唉,有点无聊啊!(偶然撇过书架)这么多书得看到什么时候啊,要不要拿一本 ...
- 《深入理解 Java 虚拟机》学习 -- Java 内存模型
<深入理解 Java 虚拟机>学习 -- Java 内存模型 1. 区别 这里要和 JVM 内存模型区分开来: JVM 内存模型是指 JVM 内存分区 Java 内存模型(JMM)是指一种 ...
- Java虚拟机系列(一)---Java内存划分
Java和C++之间有一堵由内存管理和垃圾收集技术所围成的“高墙”,墙外的人想进去,墙内的人却想出来. ------摘自<深入理解Java虚拟机> 作为一个Java程序员,因为虚拟机的好 ...
- Java内存区域与内存溢出异常——深入理解Java虚拟机 笔记一
Java内存区域 对比与C和C++,Java程序员不需要时时刻刻在意对象的创建和删除过程造成的内存溢出.内存泄露等问题,Java虚拟机很好地帮助我们解决了内存管理的问题,但深入理解Java内存区域,有 ...
随机推荐
- mfc控件与其对应的对象的关联方法
对话框的控件与其对应类的对象相关联:(两种方法) (1) 通过CWnd::DoDataExchange函数进行关联: 用VC++6.0的MFC ClassWizard中的Member Var ...
- cuzysdk购物模块 36kr+本期背景图
说好的剧透,虽然来的稍微晚不少 cuzysdk(www.cuzy.com) 是一个手机淘宝客sdk,通过使用cuzy,可以获取taobao平台的推广商品数据,移动开发者把推广的商品数据呈现给用户,用户 ...
- MFC 直线 虚线 折线 圆 椭圆 矩形 弧形
****Dlg.h头文件加入: //为project加入画笔.点变量数组 public: CPen m_pen[5]; CPoint m_point[5]; public: void DrawLine ...
- 一种基于Qt的可伸缩的全异步C/S架构server实现(一) 综述
本文向大家介绍一种基于Qt的伸缩TCP服务实现.该实现针对C/Sclient-服务集群应用需求而搭建. 连接监听.传输数据.数据处理均在独立的线程池中进行,依据特定任务不同,可安排负责监听.传输.处理 ...
- String[255]在高版本Delphi里还是被解释成Byte,总体长度256,使用StrPCopy可以给Array String拷贝字符串(内含许多实验测试)
学了好多不了解的知识: procedure TForm1.Button1Click(Sender: TObject); var s1 : String; s2 : String[]; begin s1 ...
- AngularJS 学习笔记值post传值
问题直接调用$http.post()方法时 传值格式是这样的 php接收端接收到的是json格式的,怎么做的跟Ajax post那样传值呢? 分析原因,angular的$http.post()方法默认 ...
- iOS 5 故事板入门(4)
原文: http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-2 让 AddPlayer 窗口动起来 现在,我们先 ...
- Swift - 文件,文件夹操作大全
ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现. 下面总结了各种常用的操作: 1,遍历一个目录下的所有文件 1 ...
- Eclipse 修改maven 仓储Repository位置
简述: 使用两个Nexus, 需要配置两份不同的Maven仓库 步骤: 1. 下载新的Maven运行包 2. 进入conf/ 修改setting.xml项 <localRepository> ...
- Org-mode五分钟教程ZZZ - Kaka Abel的日志 - 网易博客
Org-mode五分钟教程ZZZ - Kaka Abel的日志 - 网易博客 Org-mode五分钟教程ZZZ