码迷,mamicode.com
首页 > 编程语言 > 详细

第二章 JAVA内存区域与内存溢出异常

时间:2015-07-14 17:59:21      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:jvm

概述

Java程序员不需要自己去手动释放内存,而C、C++程序员就需要自己去操作了,原因是Java虚拟机帮我们完成了这个动作,所以我们也要了解jvm的机制,这样出问题后才会知道它到底是什么情况。本章介绍JVM内存各个区域。

运行时数据区域

根据《Java虚拟机规范(Java SE 7 版)》规定,Java虚拟机的内存包括以下几个运行时数据区域

程序计数器

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。Java虚拟机的多线程是通过线程切换并分配处理器执行时间的方式实现,程序计数器的作用就是记住当前线程执行到哪里。
当前线程所执行的字节码的行号指示器,字节码解释器就是改变当前程序计数器的行号来工作

Java虚拟机栈

英文名为 Java virtual machine stacks ,线程私有,生命周期与线程相同
每个方法在执行的时候都会创建一个栈帧(Stack Frame),方法从调用到执行的过程对应着栈帧的入栈和出栈。
栈帧的概念:用来存储局部变量表、操作数栈、动态链接、方法出口登信息。
局部变量表:存储的是编译器可知的各种基本数据类型和对象引用、returnAddress类型等,所需的内存在编译期完成分配
异常:
1. 请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常
2. 如果虚拟机栈可动态扩展时,申请不到足够的内存,抛出OutOfMemoryError异常

本地方法栈

本地方法栈和Java虚拟机栈的功能一样,只不过本地方法栈的方法是native方法

Java堆

Java虚拟机内存中最大的一块,存储对象实例和数组,线程共享区域。垃圾收集器管理的主要区域,也称GC堆。
可以处于物理上不连续的内存空间中,逻辑连续。
通过-Xmx和-Xms控制,若在堆中没有内存完成实例分配也无法扩展堆,将抛出OutOfMemoryError异常

方法区

线程共享内存,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,别名 Non-Heap(非堆)
内存回收针对的主要目标为常量池的回收和对类型的卸载(条件苛刻)
方法区无法满足内存分配需求,抛出OutOfMemoryError异常

运行时常量池

Runtime Constant Pool 方法区一部分,存放编译期生成的各种字面量和符号引用,运行期间也可能将新的常量放入池中
无法申请到内存时,抛出OutOfMemoryError异常

直接内存

Direct Memory不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但这部分内存也被频繁使用,也可导致OutOfMemoryError异常。
JDK1.4 新加入NIO,一种基于通道与缓冲区的I/O方式,可以使用native函数库直接分配堆外内存,然后通过DirectByteBuffer对象作为这块内存的引用进行操作,避免了在Java堆和Native堆中来回复制数据。

hotspot虚拟机对象探秘

对象的创建

Created with Rapha?l 2.1.0new关键字常量池中定位到一个符号引用?分配内存(内存已确认)将分配到的内存初始化为零值设置对象的对象头(e.g 哪个实例、如何找到类元数据信息、对象哈希码、对象GC分代年龄等)按程序进行初始化设置对象创建完成类加载yesno

java堆中分配内存的方法:指针碰撞(Bump the Pointer)、空闲列表(Free List)
并发操作指针非线程安全解决方案:①对分配内存空间的动作同步锁定处理、②将内存分配的动作按照线程话费到不同空间,即Thread Local Allocation Buffer,TLAB分配完并分配新的TLAB时,才需要同步锁定,虚拟机是否使用TLAB,通过-XX:+/-UseTLAB参数来设定

对象的内存布局

三块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)
- 对象头
1. 官方称为Mark Word,长度在32和64位的虚拟机中分别为32bit和64bit。存储对象自身运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。因为需要存储很多的数据,所以其被设计成一个非固定数据结构,以便利用更多的空间,其根据对象状态复用当前空间
2. 类型指针,对象指向其类元数据的指针,确定此对象为哪个类的实例。若对象为java数组,对象头中还要有一块用于记录数组长度的区域
- 实例数据
对象真正存储的有效信息,即各种类型字段类容,无论是父类还是子类的,都要记录下来
- 对齐填充
不是必然存在的。占位符的作用。HotSpot VM自动内存管理系统要求对象起始地址必须为8字节的整数倍,对象头正好为8的整数倍,因此当实例数据没有对齐时需要自动补全来完成。

对象的访问定位

Java程序需要通过栈上的reference数据来操作堆上的具体对象。由于Java虚拟机规范中没有定义此引用该如何实现,所以实现方式也是随虚拟机变化的。
主流的访问方式有:

  • 使用句柄
    技术分享

  • 直接指针
    技术分享

使用句柄访问的好处是当对象变动时,reference无需修改,只改变到对象实例的指针就行
使用直接指针的好处是,访问对象时比较快

未完,有时间继续

版权声明:本文为博主原创文章,未经博主允许不得转载。

第二章 JAVA内存区域与内存溢出异常

标签:jvm

原文地址:http://blog.csdn.net/u011506468/article/details/46797473

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!