之前看过JVM的相关知识,当时没有留下任何学习成果物,有些遗憾。这次重新复习了下,并通过博客来做下笔记(只能记录一部分,因为写博客真的很花时间),也给其他同行一些知识分享。
Java自动内存管理机制包含两部分:内存分配和内存回收,要想理解内存分配和回收的机制,则需要了解下Java内存区域(Java运行时数据区),这篇随笔将按照下面的线索进行逐步解析:
Java运行时数据区对象“已死”的判定算法垃圾收集算法垃圾收集器结束语
好,接下来我们一一来看。
一、Java运行时数据区
根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括如下几个运行时数据区域
程序计数器:用来记录当前线程所执行的字节码指令的行号指示器。字节码计时器需要通过改变改值来选取下一条需要执行的字节码指定,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个指示器来完成。程序计数器是唯一一个没有规定任何OutOfMemoryError情况的区域。Java虚拟机栈:虚拟机栈描述的是Java方法执行的内存模型,每个方法执行时都会创建一个栈帧用来存储局部变量表(存放编译器可知的各种基本数据类型、对象引用和returnAddress类型,所需的内存空间在编译器完成分配)、操作数栈、动态链接、方法出口等信息。Java虚拟机栈有两种异常情况:OutOfMemoryError(扩展时无法申请到足够内存)和StackOverflowError(线程请求的栈深度大于虚拟机所允许的深度)。本地方法栈:同Java虚拟机栈类似,只不过Java虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用Native方法服务。HotSpot直接将两个栈合二为一。也规定了两种异常:OutOfMemoryError和StackOverflowError。堆:JVM所管理的内存中最大的一块,也是GC管理的主要区域。理论上所有的对象实例和数组都要在堆上分配。堆的大小是可以扩展的,通过-Xms和-Xms控制,并且堆无法扩展的时候就会报OutOfMemoryError异常。方法区:用来存储JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是为了和堆区分开来,它也叫Non-Heap(非堆)。方法区无法满足内存分配需求时,报OutOfMemoryError异常。直接内存:并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域,但是却被经常使用。JDK1.4中新加入的NIO类,引入了基于通道和缓冲区的I/O方式,他可以直接分配对外内存,以提高性能。不收堆大小的限制,但是会受物理内存的约束。也会报OutOfMemoryError异常。
附栈到堆的关联例子(基于HotSpot):
二、对象“已死”的判定算法
由于程序计数器、Java虚拟机栈、本地方法栈都是线程独享,其占用的内存也是随线程生而生、随线程结束而回收。而Java堆和方法区则不同,线程共享,是GC的所