深入理解Java虚拟机 ch2 Java内存区域与内存溢出异常 读书笔记

part2 自动内存管理机制

   本书的第一部分主要是介绍部分,正文主要从本部分开始。本部分的核心内容如标题所示:自动内存管理机制。引用一段作者的话:

Java与C++之间有一堵由动态内存分配和垃圾护手技术所围成的“高墙”,墙外面的人想出去,墙里面的人却想出来。

  Java与C++最直观的区别就是:Java的内存是自动分配和回收的。一方面,这为内存管理提供了极大的便利性,不要像C++那样对每一片内存都悉心呵护;另一方面,要是coder对JVM一无所知的话,编程时的灵活性就大大降低,当系统出现性能问题和故障时,就会一无所措,在设计方案时也往往无法具体问题具体分析。而本部分的目的就是讲述Java自动内存管理机制,通过增加对JVM内存管理的了解,从而对性能优化故障处理等问题做到有的放矢。这样,让JVM做个贴心的大总管,管理所有的细节——内存分配和回收,自己只要负责控制大局——指定各区内存大小,指定垃圾回收器,制定服务器架构方案等即可。

  本部分由四个章节构成,其中第二章和第三章是重中之重。第四章讲了JDK工具集:只要注意其中两个可视化工具即可,之前的7个命令行工具已经集成在可视化工具中,这两个工具可以在jdk的bin文件夹下找到。第五章讲述了几个调优案例的分析和作者本人对自己的Eclipse进行运行调优的过程。本人将对第二章和第三章进行整理,本篇博文主要关注第二章。

ch2 Java内存区域与内存溢出异常

   本章主要涉及三个话题:一是JVM运行时内存分区,二是HotSpot JVM在Java堆中进行对象创建、布局和访问全过程,三是内存溢出异常测试

一 JVM运行时内存分区

   JVM运行时内存分区主要分五块两种:一种是线程私有的,一种是各线程间共享的。

  线程私有的内存分为三种:程序计数器,本地方法栈和Java虚拟机栈。

  程序计数器标志当前线程所执行的字节码程序的执行位置,用以保证程序按顺序执行。需要注意的是:程序计数器只在Java方法中起作用,执行本地方法时计数器值为空。本内存区不会抛出异常。

  Java虚拟机栈帧栈入栈和出栈的场所。栈帧是每个方法在执行时创建的用来存储局部变量表、操作数栈、动态链接、方法出入等信息的。本内存区域可能抛出StackOverFlow异常OutOfMemory异常

  本地方法栈与Java虚拟机栈除了服务对象外,完全一致:Java虚拟机栈为Java方法服务,本地方法栈为Native方法服务。

  各线程共享的内存分为两种:Java堆和方法区。

  Java堆是JVM管理的内存中最大的一块,被所有线程共享,在VM启动时创建。此区域只用于存放对象实例,且几乎所有的对象实例都存放于此(除了涉及JIT和逃逸分离技术,不懂。。)。Java堆是垃圾管理器管理的主要区域(还有就是下述的方法区),也被称为GC堆。Java堆本身也分很多区:包括新生代的Eden区和Survivor区,老年代,分配缓冲区等。Java堆可能抛出OutOfMemory异常

  方法区用以存储已被虚拟机加载的类信息、常量、静态变量和JIT编译后的代码等数据。HosSpot中以永久代的方式设计方法区。该区域内存回收的目标主要是对常量池的回收和对类型的卸装。本区域会抛出OutOfMemory异常

  最后讲下直接内存,也叫堆外内存。由名字可知,该内存与JVM无关。需要注意的是,直接内存也受总内存大小影响,在设计JVM内存的时候不要忘记直接内存的存在,否则可能会引起OutOfMemory异常。JDK中提供了DirectBuffe类,其对象在直接内存中存放。

二 HotSpot JVM在Java堆中进行对象创建、布局和访问

对象创建

  从虚拟机的角度看,当遇到new指令到对象创建完成需要经过四步:

  • 检查参数能否在常量池中定位,并检查对应的类是否被加载、解析和初始化;
  • 在类加载后,对新生对象分配内存。分配内存有指针碰撞法空闲列表法
  • 将分配到的内存空间都初始化为零值;
  • 对对象进行必要的设置。

  此时,从VM的角度看,对象已经创建完毕;但从Java程序的角度看,对象创建刚开始。

对象内存布局

   HotSpot虚拟机中,对象在内存中的布局主要是对象头和实例数据,还有就是用于对齐填充的部分。

  对象头包括两部分信息:第一部分用以存储对象自身的运行时数据,其长度与VM位数相同。第二部分为类型指针,用以指向对象的类元数据,虚拟机通过该指针来确定该对象对应的类。此外,若对象是一个Java数组,对象头中还需要有一块记录数组长度的数据。

  实例数据是对象真正存储的有效数据,其存储顺序与字段在类中的定义顺序有关。另外,为了优化,可能会将较窄的数据插入到前面的空隙中,减少对齐填充。

对象访问定位

   Java程序通过栈上的reference数据来操作堆上的具体对象。该引用定位访问堆中对象位置的方式由JVM自定,主要有句柄访问直接指针两种方法。其中,HotSpot中采用直接指针法。这部分具体内容可以看书,书上图文并茂,讲的很好。

三 内存溢出异常测试

  这里需要说明的是,关于内存溢出异常分为OutOfMemory异常StackOverflow异常。只有虚拟机栈和本地方法栈会产生StackOverflow异常;Java堆,方法区,虚拟机栈,本地方法栈和直接内存可能会产生OutOfMemory异常;程序计数区不会产生内存异常。

  可以根据以上说明自己设计异常测试或使用书中示例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值