网站首页 > java教程 正文
Full GC
在设计G1时会极力避免Full GC(以下简称FGC),但是总有一些特殊情况,如果当前并发回收的速度跟不上对象分配的速度,那么需要G1启动后备方案进行FGC。早期G1的FGC使用单线程的标记整理算法,后来为了充分发挥多核处理器的优势,JEP 307提案为G1的FGC设计了多线程标记整理算法,此时多线程的FGC的线程数量可以由-XX:ParallelGCThreads控制。
G1的多线程FGC与Parallel GC的FGC类似,是一个全局STW的过程,G1使用线程组完成垃圾回收工作,整个阶段都不允许Mutator线程运行。FGC的实现位于G1FullCollector::collect(),如代码清单11-7所示:
代码清单11-7 G1 FGC
void G1FullCollector::collect() {
phase1_mark_live_objects();
phase2_prepare_compaction();
phase3_adjust_pointers();
phase4_do_compaction();
}
正如之前所说,FGC是一个标准的标记整理算法,每个步骤提交任务给线程池,使用多线程完成,尽量减少STW时间。触发FGC的场景有很多,举例如下:
Mixed GC中如果老年代回收的速度小于对象分配或晋升的速度,会触发FGC;
YGC最后会移动存活对象到其他分区,如果此时发现没有能容纳存活对象的Region,会触发FGC;
如果没有足够的Region容纳下Humongous对象,会触发FGC;
应用程序调用System.gc()也会触发FGC。
由于FGC的全局STW性,如果频繁发生FGC是比较糟糕的信号,它暗示应用程序的特性与当前的G1参数配置不能良好契合,需要开发者找到问题并进一步调优处理。
字符串去重
如果读者对虚拟机进行过Heap Dump(-XX:+HeapDumpOnOutOfMemoryError或者jmap触发)操作,会观察到Java堆中占比最大的通常是一些byte[]对象,这些byte[]对象又通常是String的成员,即字符串对象在Java堆中占据极大比重,如果能发现重复的字符串并消除它们,会节省很大一部分内存。可以手动调用String.intern()消除重复的字符串,但这需要开发者了解哪些字符串可能发生重复,也可以使用G1的新特性自动完成字符串去重。
G1的YGC和FGC都可以触发字符串去重,只需要开启-XX:+UseStringDeduplication。在YGC的copy_to_survivor()过程中如果发现开启了自动去重选项,G1会调用G1StringDedup::enqueue_from_evacuation()自动发现可以去重的字符串,如代码清单11-8所示:
代码清单11-8 选择重复字符串
bool G1StringDedup::is_candidate_from_evacuation(...) {
// 如果对象在Eden Region,并且类型是java.lang.String
if (from_young && java_lang_String::is_instance_inlined(obj)) {
// 如果对象将要复制到Survivor Region,并且年龄小于阈值
if (to_young && obj->age() == StringDeduplicationAgeThreshold) {
return true; // 作为候选项加入G1StringDedupQueue
}
// 如果对象将要晋升到Old Region,并且年龄小于阈值if (!to_young && obj->age() < StringDeduplicationAgeThreshold) {
return true; // 作为候选项加入G1StringDedupQueue
}
}
return false;
}
void G1StringDedup::enqueue_from_evacuation(...) {
if (is_candidate_from_evacuation(...)) {
G1StringDedupQueue::push(worker_id, java_string);
}
}
G1将所有存活对象从Eden复制到Survivor Region,所有从Eden晋升到Old Region并且年龄小于-XX:StringDeduplicationAgeThreshold的对象都会被放入G1StringDedupQueue等待字符串去重线程处理。字符串去重线程即StringDedupThread,它在发现队列中存在去重候选项后会弹出对象,然后调用StringDedupTable::deduplicate,如代码清单11-9所示:
代码清单11-9 StringDedupTable::deduplicate
void StringDedupTable::deduplicate(...) {
// 如果java.lang.String的value字段为空,那么不处理
typeArrayOop value = java_lang_String::value(java_string);
if (value == NULL) {
stat->inc_skipped();
return;}
...
// 根据新对象的hash查找已有对象
typeArrayOop existing_value = lookup_or_add(value, latin1, hash);
// 如果新对象和已有对象是同一个,那么不处理
if (oopDesc::equals_raw(existing_value, value)) {
stat->inc_known();
return;
}
... // 如果是不同对象,但是包含的字符串相同,则处理它
if (existing_value != NULL) {
java_lang_String::set_value(java_string, existing_value);
stat->deduped(value, size_in_bytes);
}
}
本文给大家讲解的内容是深入解析java虚拟机:Full GC和字符串去重
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
猜你喜欢
- 2024-11-22 Excel多列去重的两种方式
- 2024-11-22 js 数组去重复
- 2024-11-22 想要优雅的Excel数据去重,还得是unique函数
- 2024-11-22 携程 & 蘑菇街 & bilibili:手写数组去重、扁平化函数
- 2024-11-22 java数组的拷贝及Arrays类
- 2024-11-22 简单学Python——NumPy库7——排序和去重
- 2024-11-22 VBA数组与字典解决方案第44讲:利用字典排重,并提取不重复值
- 2024-11-22 php怎么用array_unique()函数去除数组中重复的值?
- 2024-11-22 List怎么去重?还只会用Set互换吗?一篇文章帮你打开“新世界”
- 2024-11-22 数组、去重、排序、合并、过滤、删除
你 发表评论:
欢迎- 最近发表
-
- 五,网络安全IDA Pro反汇编工具初识及逆向工程解密实战
- 「JAVA8」- Lambda 表达式(java lambda表达式原理)
- 深入探讨Java代码保护:虚拟机保护技术的新时代
- Nginx反向代理原理详解(图文全面总结)
- 逆向拆解日本IT,哪些Java技术栈薪资溢价高
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比
- Spring Boot集成ProGuard轻松实现Java 代码混淆, Java 应用固若金汤
- 从 Java 代码逆向工程生成 UML 类图和序列图
- 人与人相处:尊重是标配,靠谱是高配,厚道是顶配
- Windows系统安装日期如何修改(windows10怎么修改安装日期)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)