`
VioletGo
  • 浏览: 12122 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
文章分类
社区版块
存档分类
最新评论

JVM内存管理机制

阅读更多

概述

针对《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》第二章的笔记;

第二章主要是讲解Java虚拟机内存的各个区域,讲解这些区域的作用、服务对象以及其中可能产生的问题;

本篇并不是全书的内容;值摘录笔者认为重要的部分;

内存区域

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

mem.jpg

程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

Java虚拟机栈

Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

经常有人把Java内存区分为堆内存(Heap)和栈内存(Stack);这种划分方式的流行只能说明大多数程序员最关注的、与对象内存分配关系最密切的内存区域是这两块。这里所指的“栈”就是现在讲的虚拟机栈,或者说是虚拟机栈中局部变量表部分。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型;

在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

动态扩展是指:JVM stack 不是被实现成固定大小;而是根据需要分配;

本地方法栈

本地方法栈(Native Method Stack)可以理解为和虚拟机栈所作用基本一致,只是本地方法栈用来执行Native方法服务。

在有些虚拟机中(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。

此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的主要区域

由于现在收集器基本都采用分代收集算法,所以Java堆中还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。细分堆只是为了更好地回收内存,或者更快地分配内存;

Java堆可以处于物理上不连续的内存空间中;如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

方法区

方法区(Method Area)是各个线程共享的内存区域;它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

对于习惯了了HotSpot虚拟机上开发、部署程序的开发者来说,很多人都更愿意把方法区称为“永久代”(Permanent Generation)

对于其他虚拟机(如BEA JRockit、IBM J9等)来说是不存在永久代的概念的

在方法区中还有一块区域是运行时常量池(Runtime Constant Pool);运行时常量池相对于Class文件常量池的一个重要特征是具备动态性;

Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。

在JDK 1.4中新加入了NIO类,引入了一种基于Channel与Buffe的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

本机直接内存的分配不会受到Java堆大小的限制;但是会受到本机总内存大小以及处理器寻址空间的限制。如果各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),会导致动态扩展时出现OutOfMemoryError异常。

-XX:MaxDirectMemorySize

This option specifies the maximum total size of java.nio (New I/O package) direct buffer allocations.

Format

-XX:MaxDirectMemorySize=size[g|G|m|M|k|K] Example

java -XX:MaxDirectMemorySize=2g myApp Default Value

The default value is zero, which means the maximum direct memory is unbounded.

需要限制直接内存可以使用: -XX:MaxDirectMemorySize=xxM限制;这个值默认是0;不限制大小; 原文地址

HotSpot虚拟机对象探秘

以常用的虚拟机HotSpot和常用的内存区域Java堆为例,探讨HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程。

对象生成

1、虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程;

2、虚拟机将为新生对象分配内存;如果内存规整;使用指针碰撞算法(指针后移n位);否则使用空闲列表算法(维护空闲列表);分配算法由垃圾回收器决定;一般Serial、ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。

3、此时从虚拟机的视角来看,一个新的对象已经产生了;但从Java程序的视角来看,对象创建才刚刚开始——一般来说,执行new指令之后会接着执行方法,这样一个真正可用的对象才算完全产生出来。

对象构成

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

对象头

HotSpot虚拟机的对象头包括两部分信息,一部分用于存储对象自身的运行时数据;另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

自身运行数据包含如下:

  • 哈希码(HashCode)
  • GC分代年龄
  • 锁状态标志
  • 线程持有的锁
  • 偏向线程ID
  • 偏向时间戳
  • 如果是数组;还必须有数组长度

类型指针是Sun HotSpot针对对象的访问定位的实现;类型指针在不同的虚拟机实现中并不一样;可能并不存在;

访问定位的实现可以基于句柄池和指针两种;

使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。

使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁

这里可以找到更详细的解释;

实例数据

存储程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来;

存储顺序会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在Java源码中定义顺序的影响。

对齐填充

由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍;当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

示例:

实例部分请直接参考:

原文地址

分享到:
评论

相关推荐

    JVM工作原理及内存管理机制

    在执行方法时JVM提供了invokestatic、invokevirtual、invokeinterface和invokespecial四种指令来执行 (1)invokestatic:调用类的static方法 (2)invokevirtual:调用对象实例的方法 (3)invokeinterface:将属性...

    JVM内存管理白皮书

    JVM提供的内存管理机制是自动的,这与其他一些编程语言需要开发者显式地进行内存管理形成鲜明对比。自动内存管理的优势在于它减轻了开发者的负担,避免了因内存管理不当而产生的诸如内存泄漏等问题。 2. 垃圾收集的...

    JVM 内存管理之道

    JVM 内存管理之道 JVM垃圾回收机制 JVM GC组合 JVM 内存监控工具

    JVM性能调优-JVM内存整理及GC回收.pdf

    本文将围绕JVM性能调优这一主题展开,重点探讨JVM内存管理机制、垃圾回收(GC)算法及其优化策略。 #### Java参数传递机制解析 首先,澄清Java中的参数传递机制是非常重要的,这有助于我们更好地理解对象在方法调用...

    java虚拟机jvm及Tomcat中的jvm有关内存的设置与调优

    ### Java虚拟机(JVM)内存设置与调优详解 ...通过对JVM内存管理机制的理解,结合具体的应用场景,开发者可以有效地避免内存溢出错误,确保应用稳定高效地运行。希望本文能为您的Java项目提供有力的技术支持。

    JVM自动内存管理机制

    Java自动内存管理机制包含两部分:内存分配和内存回收,要想理解内存分配和回收的机制,则需要了解下Java内存区域(Java运行时数据区),这篇随笔将按照下面的线索进行逐步解析:1.Java运行时数据区2.对象“已死”的...

    JVM-内存管理 2012-12.pdf

    对Java开发人员而言,理解这些内存管理机制不仅能够帮助其编写出更加稳定和高效的代码,还能在发生内存问题时迅速定位和解决问题。随着JDK版本的更新,内存管理的机制和参数也在不断地优化和演进,开发者需要不断...

    MyEclipse内存不足谈谈JVM内存

    ### MyEclipse内存不足与JVM内存管理 #### 1. 各个参数的含义 在探讨具体的参数之前,我们先来了解下JVM内存管理的基本...通过上述分析,我们可以更好地理解JVM内存管理机制以及如何解决MyEclipse内存不足的问题。

    vmmap 观察jvm内存 监控jvm jvm线程

    在Java开发过程中,对JVM(Java虚拟机)的监控是至关重要的,它能帮助我们了解应用程序的运行状态,优化性能,以及及时发现并解决内存泄漏等问题。...记住,理解JVM内存管理机制是提升Java应用性能的关键步骤。

    jvm内存的运作

    尽管如此,这种自动化管理也可能导致一些问题,如内存泄漏和内存溢出,尤其是在不了解JVM内存管理机制的情况下,这些问题往往难以定位和解决。 #### 二、JVM运行时数据区域详解 JVM在执行Java程序的过程中,会使用...

    jvm内存管理,pdf

    通过以上内容可以看出,深入理解JVM内存管理和垃圾收集机制对于提高应用程序的性能至关重要。尽管现代JVM已经非常智能,能够自动管理大部分内存相关的工作,但在面对复杂的应用场景时,仍然需要开发人员具备一定的...

    打造极速MyEclipse+由MyEclipse内存不足谈谈JVM内存

    【打造极速MyEclipse:...总之,理解JVM内存管理机制并合理配置MyEclipse的JVM参数,能有效避免内存不足问题,提高开发效率。同时,定期检查和优化内存配置,保持MyEclipse的稳定运行,是每个Java开发者必备的技能。

    JVM内存空间分配笔记

    ### JVM内存空间分配详解 #### 一、JVM内存模型概览 ...综上所述,理解JVM内存分配机制对于Java开发者来说至关重要,这不仅有助于编写高效、稳定的代码,还能在遇到性能瓶颈时快速定位问题并进行优化。

    jvm 内存分析文档

    JVM内存管理主要包括内存结构、内存分配以及垃圾回收(GC)等方面。了解这些知识对于优化Java应用程序的性能至关重要。 ### 1. JVM内存结构 #### 1.1.1 JVM内存概述 JVM内存分为几个关键区域,每个区域都有特定的...

    03-VIP-JVM内存分配机制与垃圾回收算法1

    Java虚拟机(JVM)内存分配机制和垃圾回收(Garbage Collection, GC)是Java编程中的核心概念,它们直接影响到程序的...同时,调整JVM的垃圾回收参数(如XX:NewRatio, XX:SurvivorRatio等)也可以帮助优化内存管理。

    JVM内存模型

    JVM内存模型是Java虚拟机(JVM)中的一种内存管理机制,它将内存区分为永久区内存(Permanent space)和堆内存(heap space)两大块。永久区内存用于存放加载的Class类级对象,如class本身、method、field等等,而堆...

    (二)MATJVM 内存分析工具.MAT JVM 内存分析工具.MAT JVM 内存分析工具.

    MAT JVM内存分析工具可以帮助开发者深入理解Java虚拟机(JVM)的内存管理机制,通过分析堆内存快照来识别内存消耗异常的情况。 首先,MAT提供了丰富的视图来帮助用户查看内存状态,例如“概述”视图可以快速了解堆...

    Sun JVM原理与内存管理

    本文将详细介绍Sun JDK 1.6 GC的工作原理、内存管理机制以及调优技巧。 #### 二、为什么学习GC? - **性能瓶颈**:随着应用规模的增长,GC可能成为限制应用性能和并发能力的主要因素之一。 - **避免OOM**:合理...

    SPARK内存管理机制最全!

    在Spark中,内存管理机制与JVM(Java虚拟机)有着紧密的联系。Java堆内存是JVM管理的内存区域,用于存放对象实例,而堆外内存则是不经过JVM堆直接通过Java本地接口分配的内存。堆外内存的管理赋予了Spark更高效的...

Global site tag (gtag.js) - Google Analytics