推荐各位看下周志明的《深入理解JVM虚拟机》第二版
Java 虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是:
- 程序计数器
程序计数器是一块较小的内存空间,可以把它看作当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的那一条字节码指令的地址。
- Java 虚拟机栈
当一个方法即将被运行时,Java虚拟机栈首先会在Java虚拟机栈中为该方法创建一块“栈帧”,栈帧中包含局部变量表、操作数栈、动态链接、方法出口信息等。当方法在运行过程中需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中。
当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。
- 本地方法栈
本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法区是本地方法运行的内存模型。
本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
- 堆
整个 Java 虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java 虚拟机栈、本地方法栈都是一个线程对应一个的。堆是用来存放对象的内存空间。 几乎所有的对象都存储在堆中。内存结构可进一步细分为新生代和老年代。
新生代又可被分为:Eden、From Survior、To Survior。不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。
- 方法区
Java 虚拟机规范中定义方法区是堆的一个逻辑部分。方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。它又被称为永久代 方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。
大致的结构图如下(纯手画勿喷)
其中虚拟机栈和本地方栈,程序计数器为线程独占区,堆和方法区为线程共享区。而其中的常量池在1.8之后由堆转移到了元空间。
《深入理解JVM虚拟机》里面有一句话:关于GC垃圾回收,是区别java和c的一个重要标志。墙内的人想出去,墙外的人想进来。java里面自动回收无用内存垃圾的GC,的确帮了我们很多事,让我们不用像c一样创建并回收指针。但这也有它的局限性,GC的回收并不是很及时的,它在方便我们的同时,也让我们有了很多例如内存溢出的错误。
GC回收判定
- 引用计数法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时, 计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
- 可达性分析算法(根搜索算法)
从GC Roots(每种具体实现对GC Roots有不同的定义)作为起点,向下搜索它们引用的对象,可以生成一棵引用树,树的节点视为可达对象,反之视为不可达。
GCROOT的对象范围为以下四个
虚拟机栈(帧栈中的本地变量表)中引用的对象。
方法区中静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI引用的对象。
GC回收方法
- 标记清除算法
标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
- 标记整理算法
标记-整理算法分为两个阶段:标记阶段和整理阶段。标记阶段的任务是标记出所有需要被回收的对象,整理阶段就是让所有存活对象向一端移动,然后直接清理掉边界外的内存。
- 分代回收算法
根据对象存活的生命周期将内存划分为若干个不同的区域。不同区域采用不同算法(复制算法,标记整理算法),这就是分代回收算法。
- 复制算法
他将可用内存分为两部分,每次只用一块。当这块用完后就将活着的对象移动到另一块,然后剩下的内存就是无用的,直接清除即可。
CMS: CMS是一款并发、使用标记-清除算法的gc。CMS是针对老年代进行回收的GC。 CMS以获取最小停顿时间为目的。在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景。
基本的了解就到这了,我推荐各位看下周志明的《深入理解JVM虚拟机》第二版,讲的很好。这篇博文也是我看完后的一些大致轮廓,里面还有些具体的知识点就以后再补充了。