本文是《深入理解Java虚拟机 JVM高级特性与最佳实践》的读书笔记


在介绍Java的垃圾回收方法之前,我们先来了解一下Java虚拟机在执行Java程序的过程中把它管理的内存划分为若干个不同的的数据区的什么?

1.Java运行时数据区的划分

如下图:

其中程序计数器,虚拟机栈,本地方法栈这3个区域的内存随线程而生,随线程而灭的,因此这几个区域的内存分配与回收都是有确定的,我们不需要考虑这几个区域的内存的分配与回收。而堆和方法区则不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分的内存的分配和回收都是动态的,垃圾收集器关注的就是这部分内存(堆和方法区)。

下面我们先简单介绍一下这几部分区域存放的什么东西;

  1. 程序计数器:(线程私有)当前线程所执行的字节码的行号指示器,解释器工作时就是通过改变这个计数器的值来取得下一条需要执行的指令。
  2. Java虚拟机栈:(线程私有)描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法从刻调用直到执行完成,就对应于栈帧在虚拟机栈中的入栈和出栈的过程。我们常说的栈内存就是这个。
  3. 本地方法栈:(线程私有)与Java虚拟机栈类似,只不过这是为虚拟机会用到的Native方法服务的,它也会抛出StackOverflowError和OutOfMemoryError异常。
  4. Java堆:(所有线程共享)几乎所有的对象实例都会在这里分配内存,Java堆还可以细分为新生代和老年代;
  5. 方法区:(线程共享)用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;(在某些虚拟机上也称为永久代)。

2 Java(JVM)的垃圾回收机制

2.1 哪些内存需要回收?

在Java中,都是通过可达性分析来对象是否存活的(如果对象是死的,那么它所占用的内存就是需要回收的)。可达性分析算法的基本思想就是通过一系列被称为“GC Roots”的对象开始,从这些节点向下搜索,搜索走过的路线称为引用链。当一个对象没有在任何引用链上出现,则这个对象会被判定为不可用的(死的,可回收的)。

在被可达性分析算法判定为不可用的对象,也并非是一定就是会被回收的,它们还会经历一次筛选的过程,筛选的条件就是此对象是不是要执行finalize()方法,如果对象没有覆盖finalize()方法或它的finalize()方法在上一次垃圾回收器工作时已经执行过了,则被判定为不用执行finalize()方法(对象会在这次回收中被回收),若判定为需要执行finalize()方法,则这个对象会被放置在一个F-Queue队列中,稍后虚拟机会建立一个finalizer线程(低优先级)来触发这个方法,但虚拟机不承诺会等它执行完这个方法。(也就是这个对象可能在执行finalize()方法时被回收了),如果在finalize()方法中,对象加入了任何一个引用链中,则这个对象在这次回收器工作时就不会被回收了。

在Java中,有几种可作为GC Roots对象:虚拟机栈(栈帧中的本地变量表)中引用对象。方法区中类静态属性和常量引用的对象和本地方法栈中JNI引用的对象;

2.2 垃圾回收算法

2.2.1 标记-清除(Mark-Sweep)算法

首先会利用前面的可达性分析算法标记出需要回收的对象,在标记完成后就统一回收所有被标记的对象,这个算法的缺点主要有:

  • 效率问题,在标记和清除两个过程中效率都不高;
  • 空间问题,标记清除之后会产生大量的内存碎片,碎片太多,可能导致在下次为大对象分配内存时,提前触发一次垃圾回收动作;

2.2.2 复制算法(Coping)

将可用的内存分为两块,每次只使用其中的一块,这样每次只需要顺序分配内存就可以,当一块的内存用完后,就把还存活的对象复制到另一块内存中去,然后对使用过的内存空间进行回收就可以了。(一般不会采用平均分成两块的方式,现代虚拟机一般会将内存分成一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和一块Survivor空间,回收时,将Eden空间和Survivors空间里还存活的对象复制到另一块没有使用的Survivor空间中,然后清理掉用过的空间),一般会这种算法回收新生代的内存空间;

2.2.3 标记-整理(Mark-Compact)算法

先利用可达性分析算法标记需要回收的对象,然后就让还存活的对象(出现在任何引用链中的对象)都向一端移动,然后清理掉端边界外的内存。(一般用来回收老年代的对象);

3 什么时候回收

大多数情况下,对象优先在Eden区中分配(大对象直接在老年代分配),当Eden没有足够空间时,JVM就会发起一次Minor GC。在进行Minor GC 之前,JVM会检查老年代最大可用的空间是否大于新生代所有对象的空间,如果成立,则Minor GC是安全的,否则,JVM就会去检查HandlePromotionFailure设置值是否允许担保失败。如果允许担保失败,则会继续检查老年代最大可用空间是否大于历次晋升到老年代对象的平均大小,如果是,则会尝试进行Minor GC(若失败,就会进行一次Full GC);否则就会改为进行一次Full GC;

Java的垃圾回收和内存分配策略的更多相关文章

  1. 【java虚拟机序列】java中的垃圾回收与内存分配策略

    在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...

  2. Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法

    在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...

  3. java 垃圾回收及内存分配策略

    一.在垃圾收集器对堆进行回收前,首先需要判断对象是否"存活",对已经"死去"的对象进行回收 判断对象是否存活:引用计数法和可达性分析法 引用计数法:给对象添加一 ...

  4. Java GC 垃圾回收算法 内存分配

    垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机 ...

  5. [jvm]垃圾回收与内存分配策略

    一.垃圾回收算法 概述 JVM中,当创建的对象不再被使用的时候,此时我们认为他是无用的“垃圾”:在现代主流的商用jvm中,都是通过可达性分析来判断对象是否存活的.这个算法的基本思想是通过一系列“GCR ...

  6. Java虚拟机----垃圾回收与内存分配

    一.垃圾回收的对象: 在Java的运行时数据区中,程序计数器和虚拟机栈.本地方法栈是随着线程的生灭而生灭,栈当中栈帧的大小在编译的时候已知,在方法结束之后栈帧出栈,这部分的垃圾回收是明确的,因此需要讨 ...

  7. Java虚拟机垃圾收集器与内存分配策略

    Java虚拟机垃圾收集器与内存分配策略 概述 那些内存须要回收,什么时候回收.怎样回收是GC须要完毕的3件事情. 程序计数器.虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性 ...

  8. JVM学习02:GC垃圾回收和内存分配

    JVM学习02:GC垃圾回收和内存分配 写在前面:本系列分享主要参考资料是  周志明老师的<深入理解Java虚拟机>第二版. GC垃圾回收和内存分配知识要点Xmind梳理 案例分析1-(G ...

  9. NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配

    在" .NET的堆和栈01,基本概念.值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配.我们知道:当执行一个方法的时 ...

随机推荐

  1. [LeetCode] Validate IP Address 验证IP地址

    In this problem, your job to write a function to check whether a input string is a valid IPv4 addres ...

  2. Objective-c快速入门

    对象(Class)的声明和定义 和其他的语言不同,OC的对象创建分为两个部分.声明部分(@interface)和实现部分(@implementation),且它们都必须使用@end结束. 对象的声明( ...

  3. vue.js 第三课

    1.构造器 constructor 2.属性和方法 properties methods 3.实例生命周期 instance_lifecycle   1.vue.js都是通过 var vm=new V ...

  4. python 小功能

    目录 1.上传文件 2.验证码 一.上传文件 首先了解一下 request.FILES : 字典 request.FILES 中的每一个条目都是一个UploadFile对象.UploadFile对象有 ...

  5. php stdclass转数组

    打印输出是这样 object(stdClass)[11] //object public 'xx' => string 'xxxxxx' (length=21)可用函数处理 get_object ...

  6. spring MVC入门教程

    写一个spring mvc后台传值到前台的一个小例子. 分为以下几个步骤: 1.创建web项目. 导入项目包.具体有如下: spring-aop-4.0.4.RELEASE.jar spring-be ...

  7. COGS732. [网络流24题] 试题库

    «问题描述:假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法.«编程任务: ...

  8. iMac 打包

    1.打包成 dmg 1.1.编译文件 打开工程文件之后选取Products,复制 "项目名.app" 到指定文件夹 1.2.打开磁盘工具(所有程序-> 实用工具 ->磁 ...

  9. &#65279导致页面顶部空白一行解决方法 【】

    2016年11月7日10:57:10 模板文件生成html文件之后会在body开头处加入一个可见的控制符&#65279,导致页面头部会出现一个空白行.原因是页面的编码是UTF-8 + BOM. ...

  10. SQL 一条记录的的两个字段值相同与不同的查询

    select * from (select xm,je from table) a , (select xm01,je01 from table) bwhere a.xm = b.xm01and a. ...