主要矛盾和次要矛盾_次要GC,主要GC与完整GC

主要矛盾和次要矛盾

在使用Plumbr中的GC暂停检测功能时,我被迫通过大量有关该主题的文章,书籍和演示工作。 在整个旅程中,我多次对次要,主要和完全GC事件的使用(误用)感到困惑。 这导致了这篇博客文章,我希望我设法消除一些困惑。

该帖子希望读者熟悉JVM中内置的通用垃圾收集原理。 将堆划分为Eden,幸存者和终身/旧空间,世代假设和不同的GC算法不在本文范围之内。

次要gc主要gc完整gc

次要GC

从年轻空间(由Eden和Survivor空间组成)收集垃圾称为次要GC 。 这个定义既清晰又统一。 但是,在处理次要垃圾回收事件时,您仍然应该注意一些有趣的注意事项:

  1. 当JVM无法为新对象分配空间时(例如,伊甸园已满),总是会触发次要GC。 因此,分配率越高,次要GC的执行频率就越高。
  2. 只要池已满,就将复制其全部内容,并且指针可以再次从零开始跟踪可用内存。 因此,代替经典的Mark,Sweep和Compact,使用Mark and Copy来清理Eden和Survivor空间。 因此,在伊甸园或幸存者空间内实际上没有发生碎片。 写指针始终位于使用的池的顶部。
  3. 在次要GC事件中,终身代将被有效忽略。 从终身代到年轻代的提法被认为是事实上的 GC根源。 在标记阶段,从年轻一代到终身代的引用都将被忽略。
  4. 与通常的看法相反,所有次要GC都会触发世界暂停 ,从而停止应用程序线程。 对于大多数应用程序,暂停的长度在延迟方面可以忽略不计。 如果可以将Eden中的大多数对象视为垃圾,并且永远不要将其复制到Survivor / Old空间,则为true。 如果相反的情况是正确的,并且大多数新生对象都不符合GC的条件,则次要GC暂停将开始花费更多时间。

因此,对于Minor GC而言,情况非常清楚- 每个Minor GC都会清洗年轻一代

主GC与全GC

应该注意的是,这些术语没有正式的定义。 JVM规范和垃圾收集研究论文均未提及。 但乍看之下,在我们认为对次要GC清洁年轻空间的正确认识之上建立这些定义应该很简单:

  • 主要GC正在清理使用权空间。
  • Full GC可以清理整个堆-年轻的和终身使用的空间。

不幸的是,它有点复杂和混乱。 首先,许多主要GC由次要GC触发,因此在很多情况下不可能将两者分开。 另一方面,许多现代垃圾收集仅对部分使用权空间进行清理,因此,再次使用术语“清理”仅部分正确。

这就引出了一个点,您不必担心GC是被称为Major GC还是Full GC,而应专注于确定当前的GC是停止了所有应用程序线程还是能够与应用程序线程同时进行

JVM标准工具中甚至内置了这种混淆。 我的意思最好通过一个例子来解释。 让我们比较在运行并发标记和清除收集器( -XX:+ UseConcMarkSweepGC )的JVM上跟踪GC的两种不同工具的输出

首先尝试通过jstat输出获得洞察力:

my-precious: me$ jstat -gc -t 4235 1s
Time S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   5.7 34048.0 34048.0  0.0   34048.0 272640.0 194699.7 1756416.0   181419.9  18304.0 17865.1 2688.0 2497.6      3    0.275   0      0.000    0.2756.7 34048.0 34048.0 34048.0  0.0   272640.0 247555.4 1756416.0   263447.9  18816.0 18123.3 2688.0 2523.1      4    0.359   0      0.000    0.3597.7 34048.0 34048.0  0.0   34048.0 272640.0 257729.3 1756416.0   345109.8  19072.0 18396.6 2688.0 2550.3      5    0.451   0      0.000    0.4518.7 34048.0 34048.0 34048.0 34048.0 272640.0 272640.0 1756416.0  444982.5  19456.0 18681.3 2816.0 2575.8      7    0.550   0      0.000    0.5509.7 34048.0 34048.0 34046.7  0.0   272640.0 16777.0  1756416.0   587906.3  20096.0 19235.1 2944.0 2631.8      8    0.720   0      0.000    0.720
10.7 34048.0 34048.0  0.0   34046.2 272640.0 80171.6  1756416.0   664913.4  20352.0 19495.9 2944.0 2657.4      9    0.810   0      0.000    0.810
11.7 34048.0 34048.0 34048.0  0.0   272640.0 129480.8 1756416.0   745100.2  20608.0 19704.5 2944.0 2678.4     10    0.896   0      0.000    0.896
12.7 34048.0 34048.0  0.0   34046.6 272640.0 164070.7 1756416.0   822073.7  20992.0 19937.1 3072.0 2702.8     11    0.978   0      0.000    0.978
13.7 34048.0 34048.0 34048.0  0.0   272640.0 211949.9 1756416.0   897364.4  21248.0 20179.6 3072.0 2728.1     12    1.087   1      0.004    1.091
14.7 34048.0 34048.0  0.0   34047.1 272640.0 245801.5 1756416.0   597362.6  21504.0 20390.6 3072.0 2750.3     13    1.183   2      0.050    1.233
15.7 34048.0 34048.0  0.0   34048.0 272640.0 21474.1  1756416.0   757347.0  22012.0 20792.0 3200.0 2791.0     15    1.336   2      0.050    1.386
16.7 34048.0 34048.0 34047.0  0.0   272640.0 48378.0  1756416.0   838594.4  22268.0 21003.5 3200.0 2813.2     16    1.433   2      0.050    1.484

该片段是从JVM启动后的前17秒中提取的。 根据此信息,我们可以得出结论,在12次次要GC运行之后,执行了两次完整GC运行,总共运行了50毫秒 。 您将通过基于GUI的工具(例如jconsole或jvisualvm)得到相同的确认。

在点此结论之前,让我们看一下从同一JVM启动收集的垃圾收集日志的输出。 显然-XX:+ PrintGCDetails告诉了我们一个不同而更详细的故事:

java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC eu.plumbr.demo.GarbageProducer
3.157: [GC (Allocation Failure) 3.157: [ParNew: 272640K->34048K(306688K), 0.0844702 secs] 272640K->69574K(2063104K), 0.0845560 secs] [Times: user=0.23 sys=0.03, real=0.09 secs] 
4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K->34048K(306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307 secs] [Times: user=0.25 sys=0.05, real=0.10 secs] 
... cut for brevity ...
11.292: [GC (Allocation Failure) 11.292: [ParNew: 306686K->34048K(306688K), 0.0857219 secs] 971599K->779148K(2063104K), 0.0857875 secs] [Times: user=0.26 sys=0.04, real=0.09 secs] 
12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), 0.0821774 secs] 1051788K->856120K(2063104K), 0.0822400 secs] [Times: user=0.25 sys=0.03, real=0.08 secs] 
12.989: [GC (Allocation Failure) 12.989: [ParNew: 306686K->34048K(306688K), 0.1086667 secs] 1128760K->931412K(2063104K), 0.1087416 secs] [Times: user=0.24 sys=0.04, real=0.11 secs] 
13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: 897364K(1756416K)] 936667K(2063104K), 0.0041705 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
13.102: [CMS-concurrent-mark-start]
13.341: [CMS-concurrent-mark: 0.238/0.238 secs] [Times: user=0.36 sys=0.01, real=0.24 secs] 
13.341: [CMS-concurrent-preclean-start]
13.350: [CMS-concurrent-preclean: 0.009/0.009 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
13.350: [CMS-concurrent-abortable-preclean-start]
13.878: [GC (Allocation Failure) 13.878: [ParNew: 306688K->34047K(306688K), 0.0960456 secs] 1204052K->1010638K(2063104K), 0.0961542 secs] [Times: user=0.29 sys=0.04, real=0.09 secs] 
14.366: [CMS-concurrent-abortable-preclean: 0.917/1.016 secs] [Times: user=2.22 sys=0.07, real=1.01 secs] 
14.366: [GC (CMS Final Remark) [YG occupancy: 182593 K (306688 K)]14.366: [Rescan (parallel) , 0.0291598 secs]14.395: [weak refs processing, 0.0000232 secs]14.395: [class unloading, 0.0117661 secs]14.407: [scrub symbol table, 0.0015323 secs]14.409: [scrub string table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs] [Times: user=0.14 sys=0.00, real=0.05 secs] 
14.412: [CMS-concurrent-sweep-start]
14.633: [CMS-concurrent-sweep: 0.221/0.221 secs] [Times: user=0.37 sys=0.00, real=0.22 secs] 
14.633: [CMS-concurrent-reset-start]
14.636: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

根据这些信息,我们可以看到,确实在12次次要GC运行之后,“情况有所不同”开始发生。 但是实际上,这是两个完全GC运行,而实际上,“不同的事情”只是一个在Tenured一代中运行的GC,它由不同的阶段组成:

  • 初始标记阶段,持续0.0041705秒或大约4ms。 此阶段是一个世界停止事件,它将停止所有应用程序线程以进行初始标记。
  • 同时执行Markup和Preclean阶段。 这些与应用程序线程并发运行
  • 最终备注阶段,范围为0.0462010秒或大约46ms。 此阶段再次是世界停止事件。
  • 并发执行Sweep操作。 顾名思义,此阶段也可以并发执行,而无需停止应用程序线程。

因此,我们从实际的垃圾收集日志中看到的是–代替了两次Full GC操作,实际上只执行了一次Major GC Cleaning Old空间。

如果您在等待时间之后,那么根据jstat揭示的数据做出决策将使您朝着正确的决策方向迈进。 它正确地列出了两个总计为50ms的世界停止事件,这些事件当时影响了所有活动线程的延迟。 但是,如果您尝试针对吞吐量进行优化,那么您可能会被误导-仅列出世界末日的初始标记和最终标记阶段,而jstat输出则完全隐藏了正在完成的并发工作。

结论

考虑到这种情况,最好甚至避免以次要,主要或完全GC的方式进行思考。 而是监视您的应用程序的延迟或吞吐量,并将GC事件链接到结果。 除了这些事件之外,您还需要了解特定的GC事件是强制所有应用程序线程停止还是是并发处理的事件的一部分。

如果您喜欢这些内容–这是我们的《垃圾收集手册》中的示例章节。 整个手册将于2015年3月发行。

翻译自: https://www.javacodegeeks.com/2015/03/minor-gc-vs-major-gc-vs-full-gc.html

主要矛盾和次要矛盾

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

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

相关文章

action mutation 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

module与moduleCollection你一定要会啊!Vuex源码学习(五)加工后的module在组件中使用vuex的dispatch和commit的时候,我们只要把action、mutation注册好,通过dispatch、commit调用一下方法名就可以做到。使用方式vue组件内//in vue componentt…

grunt 插件_从Grunt测试Grunt插件

grunt 插件编写针对grunt插件的测试结果比预期的要简单。 我需要运行多个任务配置,并想通过在主目录中键入grunt test来调用它们。 在第一个任务失败后,咕声通常会退出。 这使得不可能在主项目gruntfile中存储多个失败方案。 从那里运行它们将需要--for…

​嵌入式开发为什么选择C语言?

从语言特点来说C语言有出色的可移植性,能在多种不同体系结构的软/硬平台上运行。简洁紧凑,使用灵活的语法机制,并能直接访问硬件能够直接访问硬件的语言有:汇编和C语言汇编属于低级语言,难以完成一些复杂的功能&#x…

mysql 临时表 heap_mysql优化: 内存表和临时表

由于直接使用临时表来创建中间表,其速度不如人意,因而就有了把临时表建成内存表的想法。但内存表和临时表的区别且并不熟悉,需要查找资料了。一开始以为临时表是创建后存在,当连接断开时临时表就会被删除,即临时表是存…

序列化与反序列化的单例模式_序列化代理模式

序列化与反序列化的单例模式在上一篇文章中 ,我谈到了一般的序列化。 这是更加集中的内容,并提供了一个细节: 序列化代理模式 。 这是处理序列化中许多问题的一种好方法,通常是最好的方法。 如果开发人员只想了解这一主题&#xf…

图解C语言的希尔排序

希尔排序是插入排序的一种,又称“缩小增量排序”,希尔排序是直接插入排序算法的一种更高效的改进版本。希尔排序的基本思想设等待排序等元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为n/inc…

给oim_对OIM Web(UI)层进行压力测试

给oimOracle IDM中的默认配置保留20个专用于服务前端(UI)请求的线程 。 这基本上意味着应用程序服务器具有20个线程池,可用于为通过Web控制台(/ identity或/ sysadmin)访问OIM的用户提供服务。 对于Weblogic &#xf…

windows mysql is read only_mysql中Table is read only错误解决方法(转载)

下面来给各位同学介绍一下关于mysql中Table is read only的解决技巧,希望例子能帮助到各位。今天再我把数据库data 拷贝到linux 下运行程序 ”mysql中Table is read only的解决“ 出现这样的问题,查询资料。linux下执行如下命令即可#mysqladmin -u root…

C语言打印输出红色字体

除了Linux,在VS下也可以实现变色这一效果,先看下面的一段代码:#include int main(int argc,char **argv){ printf("\033[44;37;5m hello world\033[0m\n");return 0;}编译后运行上述代码,结果如下:可见&…

mysql g月份分组_PowerBI快捷键——视觉对象分组功能

PowerBI的2020年4月份更新虽然发布在5月份,但的确是提供了很多强大的功能。在以往,要选中多个视觉对象,往往需要按住CTRL键挨个单击选中,然后在进行下一步的分组或其他操作。但是在4月份更新中,PowerBI允许我们通过在画…

编译原理抽象语法树_平衡抽象原理

编译原理抽象语法树使代码复杂易读和理解的一件事是&#xff0c;方法内部的指令处于不同的抽象级别。 假设我们的应用程序仅允许登录用户查看其朋友的旅行。 如果用户不是朋友&#xff0c;则不会显示任何行程。 一个例子&#xff1a; public List<Trip> tripsByFriend…

谈谈单片机编程思想——状态机

玩单片机还可以&#xff0c;各个外设也都会驱动&#xff0c;但是如果让你完整的写一套代码时&#xff0c;却无逻辑与框架可言。这说明编程还处于比较低的水平&#xff0c;你需要学会一种好的编程框架或者一种编程思想&#xff01;比如模块化编程、状态机编程、分层思想等。本文…

C语言结构体使用与指针的理解

以前总有一种疑惑。为什么结构体的指针有的需要用分配空间&#xff1f;有的不需要分配空间呢&#xff1f;现在总结一下思路&#xff1a;一&#xff1a;关于结构体的定义问题&#xff1a;使用结构体一般会使用变量或者定义指针typedef struct{ int a; int b; }data;使用这个结构…

elementui 进度条怎么做_小E,Excel中这样的进度条是怎么做出来的?

我的目标&#xff1a;让中国的大学生走出校门的那一刻就已经具备这些office技能&#xff0c;让职场人士能高效使用office为其服务。支持我&#xff0c;也为自己加油&#xff01;前面我们分享过如何做进度条&#xff1a;《Excel进度条启示&#xff1a;专注与持续积累定会让人生出…

adf4351使用_使用ADF BC管理保存点

adf4351使用在使用ADF BC时&#xff0c;我们通常依赖于在数据库中执行DML操作的框架。 该框架在DBTransaction提交周期内正确地在数据库中进行了所有必要的更新。 很酷的事情是&#xff0c;在这种情况下&#xff0c;数据库事务将被自动管理。 因此&#xff0c;如果出现问题&…

C语言结构体描述BMP的文件格式

BMP文件的结构其实非常简单&#xff0c;就是两个结构体&#xff0b;一个可选的调色板&#xff0b;位图数据。第一个结构体是BITMAPFILEHEADER&#xff0c;第二个结构体是BITMAPINFOHEADER。然后就是可选的调色板&#xff08;RGBQUAD数组&#xff09;。最后是位图数据。第一个结…

java必读书籍_必读:Java Java

java必读书籍他们没有在Comp Sci&#xff0c;工程学或MIS中教appsec&#xff0c;但是您却学会了编程。 而且他们可能仍然没有。 因此&#xff0c;您将如何得知XSS过滤器逃避或单击劫持攻击&#xff0c;或如何真正安全地存储密码。 您的公司无力为您提供昂贵的Appsec培训&#…

php mysql 常用语句_PHP mysql基本语句指令

1 /* 选择数据库 2 use test; 3 */ 4 5 /* 显示所有的数据库 6 show databases; 7 */ 8 9 /* 删除表/数据库 10 drop database test1; 11 delete from user1 where id4; 12 */ 13 14 /* 创建表 15 CREATE TABLE user1( 16 id int primary key auto_increment1 /*选择数据库2 us…

列表流和feed流_通过流而不是列表

列表流和feed流开幕式免责声明&#xff1a;这并不总是一个好主意。 我将介绍这个想法&#xff0c;以及为什么它是一个好主意的一些原因&#xff0c;但随后我将讨论一些不太理想的实例。 懒惰 如您所知&#xff0c;我在Python中的学习几乎和在Java中一样。 我一发现Python就很喜…

mysql数据导出不完正_【MySQL】mysqldump 导出数据 常见问题

1、使用mysqldump时报错(1064)&#xff0c;这个是因为mysqldump版本太低与当前数据库版本不一致导致的mysqldump: Couldnt execute SET OPTION SQL_QUOTE_SHOW_CREATE1: You have an error in your SQL syntax; check the manual thatcorresponds to your MySQL server version…