java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)

java虚拟机学习-深入理解JVM(1)
java虚拟机学习-慢慢琢磨JVM(2)
java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制
java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)
java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
java虚拟机学习-JVM调优总结(5)
java虚拟机学习-JVM调优总结(6)
java虚拟机学习-JVM调优总结-基本垃圾回收算法(7)
java虚拟机学习-JVM调优总结-垃圾回收面临的问题(8)
java虚拟机学习-JVM调优总结-分代垃圾回收详述(9)
java虚拟机学习-JVM调优总结-典型配置举例(10)
java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)
java虚拟机学习-JVM调优总结-调优方法(12)

 

垃圾回收的瓶颈

    传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限。但是他无法解决的一个问题,就是Full GC所带来的应用暂停。在一些对实时性要求很高的应用场景下,GC暂停所带来的请求堆积和请求失败是无法接受的。这类应用可能要求请求的返回时间在几百甚至几十毫秒以内,如果分代垃圾回收方式要达到这个指标,只能把最大堆的设置限制在一个相对较小范围内,但是这样有限制了应用本身的处理能力,同样也是不可接收的。

    分代垃圾回收方式确实也考虑了实时性要求而提供了并发回收器,支持最大暂停时间的设置,但是受限于分代垃圾回收的内存划分模型,其效果也不是很理想。

    为了达到实时性的要求(其实Java语言最初的设计也是在嵌入式系统上的),一种新垃圾回收方式呼之欲出,它既支持短的暂停时间,又支持大的内存空间分配。可以很好的解决传统分代方式带来的问题。

 

增量收集的演进

    增量收集的方式在理论上可以解决传统分代方式带来的问题。增量收集把对堆空间划分成一系列内存块,使用时,先使用其中一部分(不会全部用完),垃圾收集时把之前用掉的部分中的存活对象再放到后面没有用的空间中,这样可以实现一直边使用边收集的效果,避免了传统分代方式整个使用完了再暂停的回收的情况。

    当然,传统分代收集方式也提供了并发收集,但是他有一个很致命的地方,就是把整个堆做为一个内存块,这样一方面会造成碎片(无法压缩),另一方面他的每次收集都是对整个堆的收集,无法进行选择,在暂停时间的控制上还是很弱。而增量方式,通过内存空间的分块,恰恰可以解决上面问题。

 

 

Garbage Firest(G1)

这部分的内容主要参考这里,(http://www.blogjava.net/BlueDavy/archive/2009/03/11/259230.html),这篇文章算是对G1算法论文的解读。我也没加什么东西了。

 

目标

从设计目标看G1完全是为了大型应用而准备的。

支持很大的堆

高吞吐量

  --支持多CPU和垃圾回收线程

  --在主线程暂停的情况下,使用并行收集

  --在主线程运行的情况下,使用并发收集

实时目标:可配置在N毫秒内最多只占用M毫秒的时间进行垃圾回收

当然G1要达到实时性的要求,相对传统的分代回收算法,在性能上会有一些损失。

 

算法详解

 

 G1可谓博采众家之长,力求到达一种完美。他吸取了增量收集优点,把整个堆划分为一个一个等大小的区域(region)。内存的回收和划分都以region为单位;同时,他也吸取了CMS的特点,把这个垃圾回收过程分为几个阶段,分散一个垃圾回收过程;而且,G1也认同分代垃圾回收的思想,认为不同对象的生命周期不同,可以采取不同收集方式,因此,它也支持分代的垃圾回收。为了达到对回收时间的可预计性,G1在扫描了region以后,对其中的活跃对象的大小进行排序,首先会收集那些活跃对象小的region,以便快速回收空间(要复制的活跃对象少了),因为活跃对象小,里面可以认为多数都是垃圾,所以这种方式被称为Garbage First(G1)的垃圾回收算法,即:垃圾优先的回收。

 

 

回收步骤:

 

初始标记(Initial Marking

    G1对于每个region都保存了两个标识用的bitmap,一个为previous marking bitmap,一个为next marking bitmap,bitmap中包含了一个bit的地址信息来指向对象的起始点。

    开始Initial Marking之前,首先并发的清空next marking bitmap,然后停止所有应用线程,并扫描标识出每个region中root可直接访问到的对象,将region中top的值放入next top at mark start(TAMS)中,之后恢复所有应用线程。

    触发这个步骤执行的条件为:

    G1定义了一个JVM Heap大小的百分比的阀值,称为h,另外还有一个H,H的值为(1-h)*Heap Size,目前这个h的值是固定的,后续G1也许会将其改为动态的,根据jvm的运行情况来动态的调整,在分代方式下,G1还定义了一个u以及soft limit,soft limit的值为H-u*Heap Size,当Heap中使用的内存超过了soft limit值时,就会在一次clean up执行完毕后在应用允许的GC暂停时间范围内尽快的执行此步骤;

    在pure方式下,G1将marking与clean up组成一个环,以便clean up能充分的使用marking的信息,当clean up开始回收时,首先回收能够带来最多内存空间的regions,当经过多次的clean up,回收到没多少空间的regions时,G1重新初始化一个新的marking与clean up构成的环。

 

并发标记(Concurrent Marking

    按照之前Initial Marking扫描到的对象进行遍历,以识别这些对象的下层对象的活跃状态,对于在此期间应用线程并发修改的对象的以来关系则记录到remembered set logs中,新创建的对象则放入比top值更高的地址区间中,这些新创建的对象默认状态即为活跃的,同时修改top值。

 

 

最终标记暂停(Final Marking Pause

    当应用线程的remembered set logs未满时,是不会放入filled RS buffers中的,在这样的情况下,这些remebered set logs中记录的card的修改就会被更新了,因此需要这一步,这一步要做的就是把应用线程中存在的remembered set logs的内容进行处理,并相应的修改remembered sets,这一步需要暂停应用,并行的运行。

 

 

存活对象计算及清除(Live Data Counting and Cleanup

    值得注意的是,在G1中,并不是说Final Marking Pause执行完了,就肯定执行Cleanup这步的,由于这步需要暂停应用,G1为了能够达到准实时的要求,需要根据用户指定的最大的GC造成的暂停时间来合理的规划什么时候执行Cleanup,另外还有几种情况也是会触发这个步骤的执行的:

    G1采用的是复制方法来进行收集,必须保证每次的”to space”的空间都是够的,因此G1采取的策略是当已经使用的内存空间达到了H时,就执行Cleanup这个步骤;

    对于full-young和partially-young的分代模式的G1而言,则还有情况会触发Cleanup的执行,full-young模式下,G1根据应用可接受的暂停时间、回收young regions需要消耗的时间来估算出一个yound regions的数量值,当JVM中分配对象的young regions的数量达到此值时,Cleanup就会执行;partially-young模式下,则会尽量频繁的在应用可接受的暂停时间范围内执行Cleanup,并最大限度的去执行non-young regions的Cleanup。

 

 

展望

    以后JVM的调优或许跟多需要针对G1算法进行调优了。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/289867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一分钟了解Android横竖屏 mdpi hdpi xhdpi xxhdpi xxxhdpi

DPI:每英寸像素数 简单的屏幕分辨率计算方法: DisplayMetrics metrics this.getResources().getDisplayMetrics(); float density metrics.density; int dpi metrics.densityDpi; int heightPixels metrics.heightPixels; int widthPixels metrics.widthPixels…

Eclipse在ubuntu平台不显示顶部菜单栏

1、问题 ubuntu上的eclipse用着用着特么就不显示顶部状态栏了 2、解决办法 sudo /etc/profile export UBUNTU_MENUPROXY0 reboot

利用 .NET Core 中的数据保护组件实现限时 Token

前言在业务开发时,我们常常需要生成有过期时间的 Token 凭证。比如重置密码,即使被其他人获取到链接,超过指定时间也无法操作,以保证安全性:常用的实现方式,可以使用缓存或数据库存储 Token 的过期时间。今…

CityEngine Web Scene如何在IIS下部署

CityEngine2012新增了发布Web场景的功能,可以通过本地的Web Scene Viewer打开,也可以发布到ArcGIS Online云端进行共享。如下图: 注:3ws场景包制作方法:选中模型->File->Export->Export Models…->CityE…

瀑布流

<html><head><meta charset"utf-8"><title>瀑布流</title><style type"text/css">#main {position: relative;}.box {padding: 5px;float: left;}.pic {height: auto;padding: 5px;border: 1px solid gray;border-rad…

java简易日历程序报告_简单的日历小程序(java编写)

import java.util.Scanner;public class CalendarDemo{public static void main(String[] args) {int sum 0;Scanner in new Scanner(System.in);System.out.print("请输入年份&#xff1a;");int year in.nextInt();Scanner sc new Scanner(System.in);System.o…

动态规划之石子合并

1、问题 ( 1 )路边玩法 有 n 堆石子堆放在路边,现要将石子有序地合并成一堆,规定每次只能移动相邻的两堆石子合并,合并花费为新合成的一堆石子的数量。求将这 N 堆石子合并成一堆的总花费(最小或最大)。 2、分析 ( 1 )建立最优值递归式 设 Min [i][j] 代表从第 i 堆石子到第 …

《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.1.1 确定参数...

本节书摘来华章计算机《vSphere性能设计&#xff1a;性能密集场景下CPU、内存、存储及网络的最佳设计实践》一书中的第1章 &#xff0c;第1.1节&#xff0c;[美] 克里斯托弗库塞克&#xff08;Christopher Kusek&#xff09; 著 吕南德特施皮斯&#xff08;Rynardt Spies&…

CityEngine快捷键一览表

Alt+鼠标左键:旋转 Alt+鼠标中键:平移 Alt+鼠标右键:缩放 鼠标左键:选择

WPF 使用DrawingVisual绘制高性能曲线图

一、前言项目中涉及到了心率监测&#xff0c;而且数据量达到了百万级别&#xff0c;通过WPF实现大数据曲线图时&#xff0c;尝试过最基础的Canvas来实现&#xff0c;但是性能堪忧&#xff0c;而且全部画出来也不实际。同时也尝试过找第三方的开源库&#xff0c;但是因为曲线图涉…

java 代码通用结构_java spring代码通用结构-java

src.main.java.com.company.projectname| - aop&#xff1a;类组。Spring AOP的Aspect仓库&#xff0c;是AOP的相关内容。定义了AOP切面类与织入方法。涉及Aspect&#xff0c;Around&#xff0c;PointCut&#xff0c;validator&#xff0c;SuppressWarnings&#xff0c;Logable…

数据结构(Java)——迭代器和列表的实例

感谢Java软件结构与数据结构 John Lewis Joseph chase 著 金名译 0. 迭代器关键概念&#xff08;补充理解&#xff09; 【1】迭代器是一个对象&#xff0c;它提供了一种依次访问集合中每个元素的方式。 【2】经常把集合定义为Iterable的&#xff0c;说明需要时可以提供一个迭代…

Android studio编译出现Failed to finalize session : INSTALL_FAILED_INVALID_APK

1、问题 我把项目里面的部分java文件导成jar文件&#xff0c;然后复制这个项目然后用Androi studio打开&#xff0c;导入jar编译出现这个错误 Installation failed with message Failed to finalize session : INSTALL_FAILED_INVALID_APK: Split lib_slice_7_apk was define…

Linux的SWAP分区空间不够用的情况下,如何添加SWAP分区

通常情况下&#xff0c;SWAP空间应大于或等于物理内存的大小&#xff0c;最小不应小于64M&#xff0c;通常应是物理内存的2-2.5倍。但根据不同的应用&#xff0c;应有不同的配置。如果是小的桌面系统&#xff0c;则只需要较小的SWAP空间&#xff0c;而大的服务器系统则视情况不…

地理信息科学前沿-[热词]

1. LBS Location Based Service&#xff1a;基于位置的服务&#xff0c;它是通过电信移动运营商的无线电通讯网络&#xff08;如GSM网、CDMA网&#xff09;或外部定位方式(如GPS)获取移动终端用户的位置信息&#xff08;地理坐标&#xff0c;或大地坐标&#xff09;&#xff0c…

《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.2.2 内存...

本节书摘来华章计算机《vSphere性能设计&#xff1a;性能密集场景下CPU、内存、存储及网络的最佳设计实践》一书中的第1章 &#xff0c;第1.2.2节&#xff0c;[美] 克里斯托弗库塞克&#xff08;Christopher Kusek&#xff09; 著 吕南德特施皮斯&#xff08;Rynardt Spies&a…

如何检查服务已在依赖注入容器中注册

前言依赖关系注入(DI)&#xff0c;是一种在类及其依赖项之间实现控制反转(IoC)的技术。在ASP.NET Core中&#xff0c;依赖关系注入是“一等公民”&#xff0c;被大量使用。但是有时&#xff0c;我们仅仅只需要知道服务是否在依赖注入容器中已注册。比如&#xff0c;不注册使用分…

java多核的利用率_java利用FutureTask、ExecutorService 在多核时代充分利用CPU运算

java利用FutureTask、ExecutorService 在多核时代充分利用CPU运算FutureTask、ExecutorService 相关知识&#xff0c;请看java,API一个使用FutureTask简单的例子&#xff1a;package com.spell.threads;import java.util.concurrent.Callable;import java.util.concurrent.Exec…

iOS9 Storyboard unwind segue反回传递事件时机详细步骤

当返回上一个界面且需要上一个界面做某事时&#xff0c;用unwind segue实现起来比delegate简单许多&#xff0c;甚至有时不适合用delegate来实现&#xff0c;那么我们就用unwind segue吧&#xff0c;而且像1->2->3这样的跳转,3视图可以通过unwind segue方便的返回到1、2任…

Eclipse之如何导入arr文件

1、arr文件 aar是android module中所有resource文件和编译后的java文件的总压缩包 aar除了包含class文件&#xff0c;还包含resource文件 2、eclipse如何导入arr文件 1&#xff09;、解压arr文件&#xff0c;一般可以看到很多文件&#xff0c;比如aidl文件夹&#xff0c;jni…