《深入理解Java虚拟机》读书笔记

2018-11-29  本文已影响16人  云师兄

第二部分 自动内存管理机制

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

运行时数据区域

Java虚拟机在执行Java程序的过程中将内存划分为下面多个不同区域。

程序计数器

是当前线程所执行的字节码的行号指示器。Java多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。为了线程切换后能恢复到之前的正确位置,每个线程都需要有独立的程序计数器来记录行号。程序计数器这块内存区域是“线程私有”的内存,记录的是正在执行的虚拟机字节码指令的地址。

Java虚拟机栈

Java虚拟机栈也是线程私有的,生命周期和线程相同。它描述的是Java方法执行的内存模型。每个方法执行的同时会创建一个栈帧用于保存局部变量表部分。局部变量可以是各种基本数据类型和引用类型。

本地方法栈

虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机使用到的Native方法服务。

Java堆

堆(Heap)是所有线程共享的一块内存区域,在虚拟机启动时创建,唯一目的就是存放对象实例。所有的对象实例以及数组都要在堆上分配。堆事垃圾收集器管理的主要区域,因此被称为GC堆。堆可以处于物理上不连续的内存空间中,通过-Xmx和-Xms控制。

方法区

与堆一样,是各个线程共享的内存区域,用于存储已经被虚拟机加载的类信息,常量,静态变量。

对象的创建

对象的创建

虚拟机遇到new指令时,先检查这个类是否已被加载,如果没有先执行类加载过程。加载通过后,在堆中给对象分配内存。

对象的内存布局

对象的内存布局分为三块区域:对象头Header,实例数据和对齐填充。

第三章 垃圾收集器与内存分配策略

第二章介绍了Java内存运行时区域的各个部分,其中程序计数器,虚拟机栈,本地方法栈三个区域随线程而生,随线程而灭,即内存在线程结束后随着回收了。而Java堆和方法区是线程公有的,所以垃圾收集器所关注的就是这部分内存。

确定对象是否存活

引用计数算法

给对象添加一个引用计数器,有地方引用它时,计数器值加1;引用失效时,计数器值减1;任何时刻计数器为0的对象就不可能再被引用,这就是引用计数算法。

主流Java虚拟机没有选用引用计数算法来管理内存,因为它很难解决对象之间相互循环引用的问题。

可达性分析算法

通过一系列的称为"GC Roots"的对象作为起始点往下搜索,所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连,则证明此对象不可用。

垃圾收集算法

标记-清除算法

最基础的收集算法是标记-清除(mark-Sweep)算法,后续算法基于此改进而得。分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

这个算法不足在于:

复制算法

基于标记-清除算法,提高效率产生的算法。将内存分为两块,每次只使用其中一块,当一块用完后就复制到另一块,再将用过的内存一次清理掉。这样每次只回收其中一整块内存就行,也解决了内存碎片的问题。

缺点在于可用内存减少了。

标记-整理算法

标记-整理算法标记过程和标记-清除算法过程一样,但后续过程不是直接对可回收对象清理,而是让所有存活的对象都移向一端,然后直接清理掉端边界外的内存。

分代收集算法

根据对象存活周期不同将内存分为几代。把Java堆分为新生代和老年代,根据各年代的特点采用最适当的收集算法。新生代对象少量存活,使用复制算法,老年代对象存活率高,使用标记-清除算法和标记-整理算法来进行回收。

HotSpot算法实现

3.4这节没看太懂,先TODO一下吧😂。

垃圾收集器

前面讲到了很多垃圾收集算法,垃圾收集器就是内存回收的具体实现(个人理解就是实现的产品,不同的虚拟机,不同的版本都有不同的垃圾收集器)。分别针对堆的新生代和老年代划分出各种收集器。

Serial收集器

它是一个单线程的收集器。它只有一条收集线程去完成收集工作,并且在收集过程中必须暂停其他所有的工作线程。这种“Stop the World”理念导致:垃圾回收时用户线程停顿。为解决这个问题,后产生了一些更优秀的收集器来缩短停顿时间。虽然Serial收集器有这个问题,但他还是Client模式下默认的新生代收集器。尽管有缺点,但是由于它没有线程交互的开销,专心做垃圾收集自然可以获取最高的单线程收集效率。

ParNew收集器

ParNew收集器是Serial收集器的多线程版本,其余行为和Serial收集器的实现完全一样。在单CPU环境下ParNew收集器不会比Serial收集器有更好的效果;在CPU非常多的环境下,可以使用--XX:ParallelGCThreads参数来限制垃圾收集的线程数。

Parallel Scavenge收集器

Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)所以吞吐量高就可以高效率地利用CPU时间。Parallel Scavenge提供了两个参数用于精确控制吞吐量:用-XX:MaxGCPauseMills参数控制最大垃圾收集停顿时间,或-XX:GCTimeRatio参数来直接垃圾收集时间占总时间的比率。

Serial Old收集器

Serial Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。

CMS收集器

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。全名为Concurrent Mark Sweep可以看出CMS收集器是基于标记-清除算法实现的。

G1收集器

G1是一款面向服务端应用的垃圾收集器。

内存分配与回收策略

Java技术体系中所提倡的自动内存管理最终归结为给对象分配内存以及回收内存两部分。关于回收内存,已经通过垃圾收集器去实现,接下来要讨论的就是如何给对象分配内存。

大多数情况下,对象在堆上新生代Eden区中分配。

第三部分 虚拟机执行子系统

第六章 类文件结构

运行在Java虚拟机上的语言除了Java语言外还有一些其他语言,为能在Java虚拟机上运行他们都要编译成Class文件。Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序排列在Class文件中。

上一篇下一篇

猜你喜欢

热点阅读