一、垃圾回收机制概念

不定时去堆内存中清理不可达对象。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,即使程序员能明确地判断出有一块内存已经无用了,是应该回收的,程序员也不能强制垃圾收集器回收该内存块。程序员唯一能做的就是通过调用System.gc 方法来"建议"执行垃圾收集器,但其是否可以执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。

1. finalize方法

Java使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

2. 判断对象是否存活算法

  1. 引用计数法

    引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾。这种方法的缺点就是不能检测到环的存在。首先需要声明,至少主流的Java虚拟机里面都没有选用引用计数算法来管理内存。 什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1.任何时刻计数器值为0的对象就是不可能再被使用的。那为什么主流的Java虚拟机里面都没有选用这种算法呢?其中最主要的原因是它很难解决对象之间相互循环引用的问题。

  2. 根搜索算法
    根搜索算法的基本思路就是通过一系列名为”GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
    在Java语言中,可以作为GCRoots的对象包括下面几种:
    (1). 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
    (2). 方法区中的类静态属性引用的对象。
    (3). 方法区中常量引用的对象。
    (4). 本地方法栈中JNI(Native方法)引用的对象。

3.垃圾回收机制策略

  1. 标记清除算法
    该算法有两个阶段。

    1. 标记阶段:找到所有可访问的对象,做个标记
    2. 清除阶段:遍历堆,把未被标记的对象回收

    该算法一般应用于老年代,因为老年代的对象生命周期比较长。

    优缺点:

    1. 优点

      • 是可以解决循环引用的问题
      • 必要时才回收(内存不足时)
    2. 缺点:
      • 回收时,应用需要挂起,也就是stop the world。
      • 标记和清除的效率不高,尤其是要扫描的对象比较多的时候
      • 会造成内存碎片(会导致明明有内存空间,但是由于不连续,申请稍微大一些的对象无法做到),
  2. 复制算法
    如果jvm使用了coping算法,一开始就会将可用内存分为两块,from域和to域, 每次只是使用from域,to域则空闲着。当from域内存不够了,开始执行GC操作,这个时候,会把from域存活的对象拷贝到to域,然后直接把from域进行内存清理。
    coping算法一般是使用在新生代中,因为新生代中的对象一般都是朝生夕死的,存活对象的数量并不多,这样使用coping算法进行拷贝时效率比较高。jvm将Heap 内存划分为新生代与老年代,又将新生代划分为Eden(伊甸园) 与2块Survivor Space(幸存者区) ,然后在Eden –>Survivor Space 以及From Survivor Space 与To Survivor Space 之间实行Copying 算法。 不过jvm在应用coping算法时,并不是把内存按照1:1来划分的,这样太浪费内存空间了。一般的jvm都是8:1。也即是说,Eden区:From区:To区域的比例是
    优缺点:

    1. 优点:在存活对象不多的情况下,性能高,能解决内存碎片和java垃圾回收算法之-标记清除 中导致的引用更新问题。
    2. 缺点: 会造成一部分的内存浪费。不过可以根据实际情况,将内存块大小比例适当调整;如果存活对象的数量比较大,coping的性能会变得很差。
  3. 标记压缩算法
    标记清除算法和标记压缩算法非常相同,但是标记压缩算法在标记清除算法之上解决内存碎片化。
    任意顺序 : 即不考虑原先对象的排列顺序,也不考虑对象之间的引用关系,随意移动对象;
    线性顺序 : 考虑对象的引用关系,例如a对象引用了b对象,则尽可能将a和b移动到一块;
    滑动顺序 : 按照对象原来在堆中的顺序滑动到堆的一端。

    优缺点:

    1. 优点:解决内存碎片问题
    2. 缺点压缩阶段,由于移动了可用对象,需要去更新引用。
  4. 分代算法
    这种算法,根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。可以用抓重点的思路来理解这个算法。
    新生代对象朝生夕死,对象数量多,只要重点扫描这个区域,那么就可以大大提高垃圾收集的效率。另外老年代对象存储久,无需经常扫描老年代,避免扫描导致的开销。

    新生代:

    在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;可以参看我之前写的java垃圾回收算法之-coping复制。

    老年代:

    而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记-清除-压缩”算法进行回收。参看java垃圾回收算法之-标记_清除压缩新创建的对象被分配在新生代,如果对象经过几次回收后仍然存活,那么就把这个对象划分到老年代。老年代区存放Young区Survivor满后触发minor GC后仍然存活的对象,当Eden区满后会将存活的对象放入Survivor区域,如果Survivor区存不下这些对象,GC收集器就会将这些对象直接存放到Old区中,如果Survivor区中的对象足够老,也直接存放到Old区中。如果Old区满了,将会触发Full GC回收整个堆内存。

二、JVM参数配置

JVM提供了诸多的参数进行JVM各个方面内存大小的设置,为Java应用进行优化提供了诸多的工具。

1.常见参数

-XX:+PrintGC 每次触发GC的时候打印相关日志
-XX:+UseSerialGC 串行回收
-XX:+PrintGCDetails 更详细的GC日志
-Xms 堆初始值
-Xmx 堆最大可用值
-Xmn 新生代堆最大可用值
-XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例.
-XX:NewRatio 配置新生代与老年代占比 1:2
含以-XX:SurvivorRatio=eden/from=den/to
总结:在实际工作中,我们可以直接将初始的堆大小与最大堆大小相等,
这样的好处是可以减少程序运行时垃圾回收次数,从而提高效率。
-XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例.

2. 堆内存大小配置

Java应用最大可用内存为20M, 初始内存为5M

-Xmx20m -Xms5m

打印信息:

System.out.println("最大内存"+Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.println("可用内存"+Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.println("已经使用内存"+Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");

3. 设置新生代比例参数

堆内存初始化值20m,堆内存最大值20m,新生代最大值可用1m,eden空间和from/to空间的比例为2/1, 串行回收。

-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

测试:

byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}

4. 设置新生代与老年代比例参数

堆内存初始化值20m,堆内存最大值20m,新生代最大值可用1m,eden空间和from/to空间的比例为2/1,串行回收。

-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC-XX:NewRatio=2

三、内存溢出解决

1.Java堆溢出

java.lang.OutOfMemoryError: Java heap space 堆内存溢出
设置堆内存大小:

 -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
List<Object> listObject = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("i:" + i);
Byte[] bytes = new Byte[1 * 1024 * 1024];
listObject.add(bytes);
}

解决方法:根据服务器配置适当增大堆内存大小。

2. 虚拟机栈溢出

java.lang.StackOverflowError 栈内存溢出
栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。
解决办法:设置线程最大调用深度

-Xss5m 设置最大调用深度

四、内存溢出与内存泄漏区别

Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽);而Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。内存溢出,这个好理解,说明存储空间不够大。就像倒水倒多了,从杯子上面溢出了来了一样。内存泄漏,原理是,使用过的内存空间没有被及时释放,长时间占用内存,最终导致内存空间不足,而出现内存溢出。

五、垃圾收集器

串行与并行收集器:

  1. 串行回收: JDK1.5前的默认算法 缺点是只有一个线程,执行垃圾回收时程序停止的时间比较长
  2. 并行回收: 多个线程执行垃圾回收适合于吞吐量的系统,回收时系统会停止运行

1. serial收集器

串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩;垃圾收集的过程中会Stop The World(服务暂停)一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程直到它收集结束。
特点:CPU利用率最高,停顿时间即用户等待时间比较长。
适用场景:小型应用
通过JVM参数-XX:+UseSerialGC可以使用串行垃圾回收器。

2. ParNew收集器

ParNew收集器其实就是Serial收集器的多线程版本。新生代并行,老年代串行;新生代复制算法、老年代标记-压缩
参数控制:-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制线程数量

3. parallel 收集器

Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;新生代复制算法、老年代标记-压缩采用多线程来通过扫描并压缩堆
特点:停顿时间短,回收效率高,对吞吐量要求高。
适用场景:大型应用,科学计算,大规模数据采集等。
通过JVM参数 XX:+USeParNewGC 打开并发标记扫描垃圾回收器。

4. cms收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
从名字(包含“Mark Sweep”)上就可以看出CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说要更复杂一些,整个过程分为4个步骤,包括:
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。老年代收集器(新生代使用ParNew)
优点:并发收集、低停顿
缺点:产生大量空间碎片、并发阶段会降低吞吐量

采用“标记-清除”算法实现,使用多线程的算法去扫描堆,对发现未使用的对象进行回收。
(1)初始标记
(2)并发标记
(3)并发预处理
(4)重新标记
(5)并发清除
(6)并发重置
特点:响应时间优先,减少垃圾收集停顿时间
适应场景:大型服务器等。
通过JVM参数 -XX:+UseConcMarkSweepGC设置

5. g1收集器

在G1中,堆被划分成 许多个连续的区域(region)。采用G1算法进行回收,吸收了CMS收集器特点。
特点:支持很大的堆,高吞吐量
–支持多CPU和垃圾回收线程
–在主线程暂停的情况下,使用并行收集
–在主线程运行的情况下,使用并发收集
实时目标:可配置在N毫秒内最多只占用M毫秒的时间进行垃圾回收
通过JVM参数 -XX:+UseG1GC 使用G1垃圾回收器
注意: 并发是指一个处理器同时处理多个任务。
并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。

JVM优化和垃圾回收机制相关推荐

  1. JVM GC(垃圾回收机制)

    在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当st ...

  2. JVM GC(垃圾回收机制)Minro GC,Major GC/Full GC

    在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当st ...

  3. Java Jvm 中的垃圾回收机制中的思想与算法 《对Java的分析总结》-四

    Java中的垃圾回收机制中的思想与算法 <对Java的分析总结>-四 垃圾回收机制 中的思想与算法 引用计算法 给对象中添加一个引用计数器,每当一个地方引用它的时候就将计数器加1,当引用失 ...

  4. 【JVM】Java垃圾回收机制(GC)详解

    Java垃圾回收机制(GC)详解 一.为什么需要垃圾回收? 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配不回收,但是事实并非如 ...

  5. JVM 架构解释 + 垃圾回收机制 详解(基于JDK8版本)

    文章目录 1. JVM 内存结构 2. JVM 之 堆 3. JVM 之 垃圾回收器(GC, Garbage Collector) 3.1 垃圾回收器 分类 + 组合方式 3.2 年轻代的 垃圾处理器 ...

  6. JVM中的垃圾回收机制

    文章目录 一.什么是垃圾回收 二.为什么需要垃圾回收 三.java中的四种引用类型 四.垃圾识别机制 1.引用计数算法 2.可达性分析算法 五.finalize()赋予对象重生 流程图(finaliz ...

  7. JVM架构和垃圾回收机制深入理解

    "七月的风,八月的雨,卑微的我,喜欢遥远的你" ,第一次听到这句歌词时,就很喜欢它,因为喜欢所以卑微,因为喜欢所以低到尘埃,就如张爱玲所说的,"见了他,她变得很低很低,低 ...

  8. jvm gc垃圾回收机制和参数说明amp;amp;Java JVM 垃圾回收(GC 在什么时候,对什么东西,做了什么事情)

    jvm gc(垃圾回收机制) Java JVM  垃圾回收(GC 在什么时候,对什么东西,做了什么事情) 前言:(先大概了解一下整个过程) 作者:知乎用户 链接:https://www.zhihu.c ...

  9. JVM垃圾回收机制(超级无敌认真好用,万字收藏篇!!!!)

    文章目录 JVM垃圾回收机制 1 判断对象是否存活的算法 1.1 引用计数器算法 1.2 可达性分析算法 2 对象的四种引用方式 2.1 强引用 2.2 软引用 2.3 弱引用 2.4 虚引用 3 垃 ...

最新文章

  1. ADA4530静电计放大器
  2. datatables 一行数据生成两行_一行代码搞定分组回归
  3. REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED
  4. java.net.Socket 解析
  5. 进阶中级程序员需要做的事
  6. c语言 二进制输出_收藏!C语言入门基础知识大全
  7. 一键锁屏_ios快捷指令一键登录校园网(桂航为例,哆点认证)
  8. 使用 Gitolite 搭建 Git 服务器
  9. mORMot Js对象解析 Json 实例
  10. linux apache 停止命令,linux 下 apache启动、停止、重启命令
  11. Docker安装java环境并部署jar包运行
  12. SRS4.0源码分析-SrsRecvThread::cycle
  13. 解决【v-show 有时失效】问题
  14. 中台技术爆发,这个软件定义中台专利指出了数字化转型路径
  15. 「杀毒」卡巴斯基 5.0.388 单机简体中文专业版
  16. 运筹GTD,决胜Future. Omnifocus2使用教程 详解 如何使用
  17. 看看大佬们最近写的文章
  18. 在线代理 网页代理 ip代理 在线代理ip 代理ip 网页代理ip ip在线代理
  19. TRIO控制器最新编程软件MotionPerfect_4_3_2_16651
  20. 聚类分析 python_Kmeans聚类算法 python sklearn 用户画像

热门文章

  1. C 语言规定 程序中各函数之间( ),C语言规定,程序中各函数之间( )
  2. win10局域网共享打印机
  3. 2021全球分布式云大会,腾讯云存储斩获分布式存储运营领袖奖
  4. idea打成war包
  5. 为什么互联网公司不招 32 岁以上的码农?
  6. 2011年9月《安全天下事之手机是怎样变成手雷的》
  7. Delft3D模型的各领域应用
  8. AutoCAD可以把三维模型拆为二维零件吗
  9. 八年级计算机考试中考成绩查询,中考成绩查询系统入口
  10. ISTQB AL高级认证考试资料(中文)