GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — 突破Java面试系列 · MrWang5200/JavaEdge-Tutorial@a192e7f

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • Java
    • JAVA-Calendar.md
    • JVM
      • JVM实战---内存模型.md
      • JVM实战---垃圾收集器.md
      • JVM实战---垃圾收集算法.md
      • JVM实战---对象实例化.md
      • JVM实战---探秘HotSpot虚拟机对象.md
      • JVM实战---类加载的过程.md
      • JVM性能调优实战(〇)---简介.md
      • JVM性能调优实战(一)---基于JDK命令行的监控.md
      • JVM性能调优实战(七)---GC-调优.md
      • JVM性能调优实战(二)---VM-监控.md
      • JVM性能调优实战(八)---Java代码层调优(字节码指令).md
      • JVM指令.md
      • JVM源码分析之synchronized.md
    • Java-Fork-Join-框架.md
    • Java-Map的containsKey(Object-key)和containsValue(Object-value)方法.md
    • Java-泛型解惑之---extends-T-和---super-T-.md
    • Java-源码解析实战---ThreadLocal-原理.md
    • Java-的注解.md
    • Java-类加载器.md
    • Java8-原子弹类之LongAdder源码分析.md
    • Java8流编Stream-DistinctOps,-SliceOps.md
    • Java8集合源码解析-Hashtable源码剖析.md
    • Java与线程.md
    • Java中Collections-sort()方法的演变.md
    • Java中正则表达式.md
    • Java中的BlockingQueue.md
    • Java中的VO,PO等.md
    • Java中的锁优化.md
    • Java中类型参数“-T-”和无界通配符“---”的区别.md
    • Java内存模型与volatile关键字.md
    • Java动态代理模式jdk和cglib.md
    • Java多线程中join方法的理解.md
    • Java对象序列化底层原理源码解析.md
    • Java开发人员必备linux命令.md
    • Java异常之IllegalMonitorStateException.md
    • Java性能调优工具之JDK命令行.md
    • Java源码解析---ThreadPoolExecutor-线程池.md
    • Java语法糖.md
    • Java集合源码解析---HashMap.md
    • Spring Boot
      • SpringBoot+Security-发送短信验证码.md
      • SpringBoot-三大基本注解.md
      • SpringBoot-多模块.md
      • SpringBoot2-0响应式编程系列(一)-导读.md
      • SpringBoot统一异常处理.md
      • SpringBoot集成BootStrap.md
      • SpringBoot集成RabbitMQ.md
      • SpringBoot集成Thymeleaf模板.md
      • Springboot-秒杀项目.md
      • Springboot集成Thymeleaf.md
    • Spring Cloud
      • SpringCloud-广告系统实战(七)----广告检索系统(加载全量索引).md
      • SpringCloud-广告系统实战(三)---通用模块的开发.md
      • SpringCloud-广告系统实战(二)---搭建脚手架.md
      • SpringCloud-广告系统实战(五)---广告检索系统(微服务调用).md
      • SpringCloud-广告系统实战(六)----广告检索系统(广告数据索引的设计与实现).md
      • SpringCloud-广告系统实战(四)---投放系统的开发.md
      • SpringCloud-广告系统设计与实现(一)---概述.md
      • SpringCloud微服务实战(一)-简介.md
      • SpringCloud微服务实战(七)-异步和消息.md
      • SpringCloud微服务实战(七)-消息服务在电商中的实践.md
      • SpringCloud微服务实战(三)-服务注册与发现.md
      • SpringCloud微服务实战(二)-微服务介绍.md
      • SpringCloud微服务实战(六)-统一配置中心.md
      • SpringCloud微服务实战(十)-Hystrix.md
      • SpringCloud微服务实战(四)-微服务中的服务拆分.md
    • Spring
      • @Autowired-与@Resource之争.md
      • Spring--Http源码.md
      • Spring-5-0中文版-3-9.md
      • Spring-Bean的作用域管理.md
      • Spring-Bean的生命周期.md
      • Spring-事务管理.md
      • Spring-实战---IoC容器的依赖注入.md
      • SpringBean.md
      • SpringMVC 工作原理详解.md
      • SpringMVC-Restful.md
      • SpringMVC-的处理拦截器.md
      • SpringMVC之@CookieValue注解.md
      • SpringMVC之Controller查找(Spring4-0-3-Spring5-0-4源码进化对比).md
      • SpringMVC全局异常.md
      • SpringMVC数据绑定.md
      • SpringMVC的@ResponseBody注解说明.md
      • Spring学习与面试.md
      • Spring源码解析-IoC容器的初始化过程(上).md
    • 并发编程
      • Java并发编程实战系列10之避免活跃性危险.md
      • Java并发编程实战系列11之性能与可伸缩性Performance-and-Scalability.md
      • Java并发编程实战系列13之显式锁-(Explicit-Locks).md
      • Java并发编程实战系列14之构建自定义的同步工具-(Building-Custom-Synchronizers).md
      • Java并发编程实战系列15之原子遍历与非阻塞同步机制(Atomic-Variables-and-Non-blocking-Synchron.md
      • Java并发编程实战系列16之Java内存模型(JMM).md
      • Java并发编程实战系列5之基础构建模块.md
      • Java并发编程实战系列6之任务执行(Task-Execution).md
      • Java并发编程实战系列7之取消与关闭.md
      • Java并发编程实战系列8之线程池的使用.md
      • Java并发编程知识点全总结.md
      • 史上最快Docker入门!(一)-容器技术和Docker简介.md
  • 职业发展
    • 漫漫大学江湖录 - 爱与恨唯与工作更交织.md
  • 面试系列
    • 突破Java面试系列
      • 突破Java面试(00) - 说明.md
      • 突破Java面试(01)-现代互联网java工程师招聘JD.md
      • 突破Java面试(02) - Redis如何通过读写分离来承载读请求QPS超过10万+?.md
      • 突破Java面试(03)-关于互联网Java工程师面试突击训练课程的几点说明.md
      • 突破Java面试(05)- 消息队列技术选型.md
      • 突破Java面试(06)-如何保证消息队列的高可用性.md
      • 突破Java面试(07)-如何保证消息队列不重复消费数据.md
      • 突破Java面试(10)-百万消息在消息队列里积压了几个小时.md
      • 突破Java面试(11)-你怎么设计一个消息队列?.md
      • 突破Java面试(12) - 总结消息队列相关问题的面试技巧.md
      • 突破Java面试(13)分布式搜索引擎连环炮.md
      • 突破Java面试(14)-分布式搜索引擎的架构.md
      • 突破Java面试(15)-分布式搜索引擎Elastic Search的工作流程.md
      • 突破Java面试(17)-你们公司生产环境的分布式搜索引擎是怎么部署的呢.md
      • 突破Java面试(18)-消息队列面试技巧总结.md
      • 突破Java面试(19) - 分布式缓存的第一个问题.md
      • 突破Java面试(20)-Redis线程模型.md
      • 突破Java面试(21) - redis有哪些数据类型,谈谈适用场景.md
      • 突破Java面试(22) - Redis的过期策略?手写一个LRU?.md
      • 突破Java面试(23)-如何保证redis高并发及高可用.md
      • 突破Java面试(23-4)-再深入Redis Replication的完整执行流程及原理.md
      • 突破Java面试(23-6)-主从架构下的Redis如何做到高可用性.md
      • 突破Java面试(23-7) - Redis的哨兵架构.md
      • 突破Java面试(23-8) - Redis哨兵主备切换的数据丢失问题.md
      • 突破Java面试(23-9) - 深入解析Redis哨兵底层原理.md
      • 突破Java面试(24)-Redis的持久化机制.md
      • 突破Java面试(25) - Redis cluster集群模式的原理.md
      • 突破Java面试(26)-说说如何应对缓存雪崩以及穿透问题.md
      • 突破Java面试(27) - 如何保证缓存与数据库的数据一致性.md
      • 突破Java面试(28) - 如何解决Redis的并发竞争问题.md
      • 突破Java面试(29) - 生产环境的redis集群的部署架构是怎么样的.md
      • 突破Java面试(30) - 分布式缓存面试题回答技巧总结.md
      • 突破Java面试(31)-分布式系统连环炮.md
      • 突破Java面试(32)-为什么要把系统拆分成分布式的?为啥要用dubbo.md
      • 突破Java面试(33)-Dubbo的工作原理.md
      • 突破Java面试(34)-dubbo支持的协议.md
      • 突破Java面试(35)-Dubbo负载均衡及动态代理的策略.md
      • 突破Java面试(36)-聊聊Dubbo的SPI机制.md
      • 突破Java面试(37)-基于Dubbo的服务治理、服务降级以及重试.md
      • 突破Java面试(38)-分布式服务接口的幂等性.md
      • 突破Java面试(39)-分布式服务接口请求的顺序性.md
      • 突破Java面试(40)-如何设计一个类似Dubbo的RPC框架.md
      • 突破Java面试(41)-ZooKeeper的适用场景.md
      • 突破Java面试(42) - Redis & ZooKeeper两种分布式锁实现的优劣.md
      • 突破Java面试(43)-分布式Session方案的实现.md
      • 突破Java面试(44)-分布式事务解决方案.md
      • 突破Java面试(45)-高并发系统的架构设计.md
      • 突破Java面试(46)-分库分表.md
      • 突破Java面试(47)-分库分表的实践.md
      • 突破Java面试(48)-设计可动态扩容缩的分库分表.md
      • 突破Java面试(49)-分库分表之后全局id的生成.md
      • 突破Java面试(50)-MySQL读写分离及主从同步延时解决方案.md
      • 突破Java面试(8)-MQ的数据去哪了.md
      • 突破Java面试(9)-如何保证消息队列的顺序性.md
      • 突破Java面试(53)- 分布式架构的演进过程.md
    • 高可用系统架构的设计
      • 1.md
      • 13_开发品牌名称获取接口的基于本地缓存的fallback降级机制.md
      • 突破Java面试-hystrix分布式系统可用性及设计原则.md
      • 高可用服务架构设计(10)-Hystrix的线程池+服务+接口划分以及资源池的容量大小控制.md
      • 高可用服务架构设计(12) - 基于request cache请求缓存技术优化批量商品数据查询接口.md
      • 高可用服务架构设计(16) - 基于timeout机制来为商品服务接口的调用超时提供安全保护.md
      • 高可用服务架构设计(17) - 基于Hystrix的高可用分布式系统架构设计的总结.md
      • 高可用服务架构设计(9) - 基于Hystrix的信号量技术对地理位置获取逻辑进行资源隔离与限流.md
      • 高可用架构设计(0) - 导读.md
      • 高可用架构设计(1) - hystrix与高可用系统架构:资源隔离+限流+熔断+降级+运维监控.md
      • 高可用架构设计(2) - hystrix要解决的分布式系统可用性问题以及其设计原则.md
      • 高可用架构设计(3) -电商商品详情页缓存背景及框架说明.md

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎Java/JAVA-Calendar.md‎

Copy file name to clipboard
+53Lines changed: 53 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与通过 new GregorianCalendar() 获得的结果一致)。
2+
3+
#Calendar 与 Date 的转换
4+
Calendar calendar = Calendar.getInstance();
5+
// 从一个 Calendar 对象中获取 Date 对象
6+
Date date = calendar.getTime();
7+
// 将 Date 对象反应到一个 Calendar 对象中,
8+
// Calendar/GregorianCalendar 没有构造函数可以接受 Date 对象
9+
// 所以我们必需先获得一个实例,然后设置 Date 对象
10+
calendar.setTime(date);
11+
#注意的事项:
12+
##1. Calendar 的 set() 方法
13+
14+
set(int field, int value) - 是用来设置"年/月/日/小时/分钟/秒/微秒"等值
15+
16+
field 的定义在 Calendar 中
17+
18+
set(int year, int month, int day, int hour, int minute, int second) 但没有
19+
20+
set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不会自动将 MilliSecond 清为 0。
21+
22+
另外,月份的起始值为0而不是1,所以要设置八月时,我们用7而不是8。
23+
24+
calendar.set(Calendar.MONTH, 7);
25+
26+
我们通常需要在程序逻辑中将它清为 0, Calendar 不是马上就刷新其内部的记录
27+
28+
在 Calendar 的方法中,get() 和 add() 会让 Calendar 立刻刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。
29+
##add() 与 roll() 的区别
30+
31+
add() 的功能非常强大,add 可以对 Calendar 的字段进行计算。如果需要减去值,那么使用负数值就可以了,如 add(field, -value)。
32+
33+
add() 有两条规则:
34+
35+
当被修改的字段超出它可以的范围时,那么比它大的字段会自动修正。如:
36+
Calendar cal1 = Calendar.getInstance();
37+
cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
38+
cal1.add(Calendar.MONTH, 1); //2000-9-31 => 2000-10-1,对吗?
39+
System.out.println(cal1.getTime()); //结果是 2000-9-30
40+
41+
另一个规则是,如果比它小的字段是不可变的(由 Calendar 的实现类决定),那么该小字段会修正到变化最小的值。
42+
43+
以上面的例子,9-31 就会变成 9-30,因为变化最小。
44+
45+
Roll() 的规则只有一条:
46+
当被修改的字段超出它可以的范围时,那么比它大的字段不会被修正。如:
47+
48+
Calendar cal1 = Calendar.getInstance();
49+
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
50+
cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 周二
51+
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
52+
cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 周日
53+
WEEK_OF_MONTH 比 MONTH 字段小,所以 roll 不能修正 MONTH 字段。
Collapse file

‎Java/JVM/JVM实战---内存模型.md‎

Copy file name to clipboardExpand all lines: Java/JVM/JVM实战---内存模型.md
+403Lines changed: 403 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Large diffs are not rendered by default.
Collapse file

‎Java/JVM/JVM实战---垃圾收集器.md‎

Copy file name to clipboard
+221Lines changed: 221 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
使用分代垃圾收集器,基于以下观察事实(弱分代假设)
2+
- 大多数分配对象的存活时间短
3+
- 存活时间久的对象很少引用存活时间短的对象
4+
5+
由此, HotSpot VM 将堆分为两个物理区空间,这就是分代(永久代只存储元数据, eg. 类的数据结构,保留字符串( Interned String))
6+
7+
8+
根据新生代和老年代各自的特点,我们应该分别为它们选择不同的收集器,以提升垃圾回收效率.
9+
![](http://upload-images.jianshu.io/upload_images/4685968-3a367913acebef67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
10+
11+
# 1 新生代垃圾收集器
12+
13+
## 1.1 Serial垃圾收集器
14+
一个主要应用于Y-GC的垃圾回收器,采用串行单线程的方式完成GC任务,其中“Stop The World"简称STW,即垃圾回收的某个阶段会暂停整个应用程序的执行
15+
F-GC的时间相对较长,频繁FGC会严重影响应用程序的性能
16+
![Serial 回收流程](https://upload-images.jianshu.io/upload_images/4685968-407a95f442c62819.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
17+
`单线程 Stop-The-World 式`
18+
![](http://upload-images.jianshu.io/upload_images/4685968-ebdf41221960630c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
19+
- 单线程
20+
只会使用一个CPU或一条GC线程进行GC,并且在GC过程中暂停其他所有的工作线程,因此用户的请求或图形化界面会出现卡顿
21+
- 适合Client模式
22+
一般客户端应用所需内存较小,不会创建太多的对象,而且堆内存不大,因此GC时间比较短,即使在这段时间停止一切用户线程,也不会感到明显停顿
23+
- 简单高效
24+
由于Serial收集器只有一条GC线程,避免了线程切换的开销
25+
- 采用"复制"算法
26+
## 1.2 ParNew垃圾收集器
27+
ParNew是Serial的多线程版本.
28+
![](http://upload-images.jianshu.io/upload_images/4685968-e4947c56e4c734f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
29+
## 2.1 多线程并行执行
30+
ParNew由多条GC线程并行地进行垃圾清理.
31+
但清理过程仍然需要暂停一切其他用户线程.
32+
但由于有多条GC线程同时清理,清理速度比Serial有一定的提升
33+
## 2.2 适合多CPU的服务器环境
34+
由于使用多线程,是许多运行在 server 模式下的虚拟机首选的新生代收集器
35+
- 与Serial性能对比
36+
ParNew和Serial唯一区别就是使用了多线程垃圾回收,在多CPU的环境下性能比Serial会有一定程度的提升
37+
但线程切换需要额外的开销,因此在单CPU环境中表现不如Serial,双CPU环境也不一定就比Serial高效
38+
默认开启的收集线程数与CPU数量相同
39+
## 2.3 采用"复制"算法
40+
## 2.4 追求"降低停顿时间"
41+
和Serial相比,ParNew使用多线程的目的就是缩短GC时间,从而减少用户线程被停顿的时间
42+
# 3 Parallel : 吞吐量为先!
43+
## 3.1 Scavenge垃圾收集器
44+
Parallel Scavenge和ParNew一样都是并行的多线程、新生代收集器,都使用"复制"算法(`Stop-The-World`)进行垃圾回收
45+
46+
但它们有个巨大不同点:
47+
- ParNew收集器追求降低GC时用户线程的停顿时间,适合交互式应用,良好的反应速度提升用户体验.
48+
- Parallel Scavenge追求可控的CPU吞吐量,能够在较短的时间内完成指定任务,适合不需太多交互的后台运算
49+
50+
>吞吐量是指用户线程运行时间占CPU总时间的比例.
51+
>CPU总时间包括 : 用户线程运行时间 和 GC线程运行的时间.
52+
> 因此,吞吐量越高表示用户线程运行时间越长,从而用户线程能够被快速处理完.
53+
54+
- 降低停顿时间的两种方式
55+
1.在多CPU环境中使用多条GC线程,从而垃圾回收的时间减少,从而用户线程停顿的时间也减少;
56+
2.实现GC线程与用户线程并发执行。所谓并发,就是用户线程与GC线程交替执行,从而每次停顿的时间会减少,用户感受到的停顿感降低,但线程之间不断切换意味着需要额外的开销,从而垃圾回收和用户线程的总时间将会延长。
57+
58+
- Parallel Scavenge提供的参数
59+
- -XX:GCTimeRadio
60+
直接设置吞吐量大小,GC时间占总时间比率.相当于是吞吐量的倒数.
61+
62+
- -XX:MaxGCPauseMillis
63+
设置最大GC停顿时间
64+
Parallel Scavenge会根据这个值的大小确定新生代的大小.
65+
这个值越小,新生代就越小,从而收集器就能以较短时间进行一次GC
66+
但新生代变小后,回收的频率就会提高,吞吐量也降下来了,因此要合理控制这个值
67+
- -XX:+UseAdaptiveSizePolicy
68+
开启GC **自适应的调节策略(区别于ParNew)**.
69+
我们只要设置最大堆(-Xmx)和MaxGCPauseMillis或GCTimeRadio,收集器会自动调整新生代的大小、Eden和Survior的比例、对象进入老年代的年龄,以最大程度上接近我们设置的MaxGCPauseMillis或GCTimeRadio
70+
## 3.2 Old垃圾收集器
71+
Parallel Scavenge的老年代版本,一般它们搭配使用,追求CPU吞吐量
72+
73+
它们在垃圾收集时都是由多条GC线程并行执行,并暂停一切用户线程,使用"标记-整理"算法.因此,由于在GC过程中没有使垃圾收集和用户线程并行执行,因此它们是追求吞吐量的垃圾收集器.
74+
![](http://upload-images.jianshu.io/upload_images/4685968-7dfdda76a61a31cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
75+
# **老年代垃圾收集器**
76+
# 1 Serial Old垃圾收集器
77+
Serial的老年代版本,都是单线程收集器,GC时只启动一条GC线程,因此都适合客户端应用.
78+
79+
80+
它们唯一的区别就是
81+
- Serial Old工作在老年代,使用"标记-整理"算法
82+
- Serial工作在新生代,使用"复制"算法.
83+
![](http://upload-images.jianshu.io/upload_images/4685968-b150a60a1bae36a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
84+
85+
# 4 CMS垃圾收集器(Concurrent Mark Sweep Collector) : 低延迟为先!
86+
回收停顿时间比较短、目前比较常用的垃圾回收器。它通过初始标记(InitialMark)、并发标记(Concurrent Mark)、重新标记( Remark)、并发清除( Concurrent Sweep )四个步骤完成垃圾回收工作
87+
由于CMS采用的是“标记-清除算法",因此戸生大量的空间碎片。为了解决这个问题,CMS可以通过配置
88+
```
89+
-XX:+UseCMSCompactAtFullCollection
90+
```
91+
参数,强制JVM在FGC完成后対老年代迸行圧縮,执行一次空间碎片整理,但是空间碎片整理阶段也会引发STW。为了减少STW次数,CMS还可以通过配置
92+
```
93+
-XX:+CMSFullGCsBeforeCompaction=n
94+
```
95+
参数,在执行了n次FGC后, JVM再在老年代执行空间碎片整理
96+
97+
对许多应用来说,快速响应比端到端的吞吐量更为重要
98+
99+
管理新生代的方法与 parallel 和 serial 相同
100+
在老年代则尽可能并发执行,每个 GC 周期只有2次短的停顿
101+
102+
一种追求最短停顿时间的收集器
103+
在GC时使得用户线程和GC线程并发执行,因此在GC过程中用户也不会感受到明显卡顿
104+
但用户线程和GC线程之间不停地切换会有额外的开销,因此垃圾回收总时间就会被延长
105+
**垃圾回收过程**
106+
前两步需要"Stop The World"
107+
- 初始标记 (Initial Mark)
108+
停止一切用户线程,仅使用一条初始标记线程对所有与GC Roots直接相关联的 老年代对象进行标记,速度很快
109+
- 并发标记 (Concurrent Marking Phase)
110+
使用多条并发标记线程并行执行,并与用户线程并发执行.此过程进行可达性分析,标记所有这些对象可达的存货对象,速度很慢
111+
- 重新标记 ( Remark)
112+
因为并发标记时有用户线程在执行,标记结果可能有变化
113+
停止一切用户线程,并使用多条重新标记线程并行执行,重新遍历所有在并发标记期间有变化的对象进行最后的标记.这个过程的运行时间介于初始标记和并发标记之间
114+
- 并发清除 (Concurrent Sweeping)
115+
只使用一条并发清除线程,和用户线程们并发执行,清除刚才标记的对象
116+
这个过程非常耗时
117+
![](http://upload-images.jianshu.io/upload_images/4685968-fb1723e25639cf21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
118+
## 4.1 **CMS的缺点**
119+
- 吞吐量低
120+
由于CMS在GC过程用户线程和GC线程并行,从而有线程切换的额外开销
121+
因此CPU吞吐量就不如在GC过程中停止一切用户线程的方式来的高
122+
- 无法处理浮动垃圾,导致频繁Full GC
123+
由于垃圾清除过程中,用户线程和GC线程并发执行,也就是用户线程仍在执行,那么在执行过程中会产生垃圾,这些垃圾称为"浮动垃圾"
124+
如果CMS在GC过程中,用户线程需要在老年代中分配内存时发现空间不足,就需再次发起Full GC,而此时CMS正在进行清除工作,因此此时只能由Serial Old临时对老年代进行一次Full GC
125+
- 使用"标记-清除"算法产生碎片空间
126+
由于CMS使用了"标记-清除"算法, 因此清除之后会产生大量的碎片空间,不利于空间利用率.不过CMS提供了应对策略:
127+
- 开启-XX:+UseCMSCompactAtFullCollection
128+
开启该参数后,每次FullGC完成后都会进行一次内存压缩整理,将零散在各处的对象整理到一块儿.但每次都整理效率不高,因此提供了以下参数.
129+
- 设置参数-XX:CMSFullGCsBeforeCompaction
130+
本参数告诉CMS,经过了N次Full GC过后再进行一次内存整理.
131+
132+
# 5 G1收集器(Garbage-First)
133+
Hotspot 在JDK7中推出了新一代 G1 ( Garbage-First Garbage Collector )垃圾回收,通过
134+
```
135+
-XX:+UseG1GC
136+
```
137+
参数启用
138+
和CMS相比,Gl具备压缩功能,能避免碎片向題,G1的暂停时间更加可控。性能总体还是非常不错的,G1是当今最前沿的垃圾收集器成果之一.
139+
140+
## 5.1 G1的特点
141+
- 追求停顿时间
142+
- 多线程GC
143+
- 面向服务端应用
144+
- 整体来看基于标记-整理和局部来看基于复制算法合并
145+
不会产生内存空间碎片
146+
- 可对整个堆进行垃圾回收
147+
- 可预测的停顿时间
148+
## 5.2 G1的内存模型
149+
没有新生代和老年代的概念,而是将Java堆划分为一块块独立的大小相等的Region.
150+
当要进行垃圾收集时,首先估计每个Region中的垃圾数量,每次都从垃圾回收价值最大的Region开始回收,因此可以获得最大的回收效率
151+
![](https://upload-images.jianshu.io/upload_images/4685968-db8d827f816cca34.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
152+
G1将Java堆空间分割成了若干相同大小的区域,即region
153+
包括
154+
- Eden
155+
- Survivor
156+
- Old
157+
- Humongous
158+
159+
其中,`Humongous `是特殊的Old类型,专门放置大型对象.
160+
这样的划分方式意味着不需要一个连续的内存空间管理对象.G1将空间分为多个区域,**优先回收垃圾最多**的区域.
161+
G1采用的是**Mark-Copy** ,有非常好的空间整合能力,不会产生大量的空间碎片
162+
G1的一大优势在于可预测的停顿时间,能够尽可能快地在指定时间内完成垃圾回收任务
163+
在JDK11中,已经将G1设为默认垃圾回收器,通过jstat命令可以查看垃圾回收情况,在YGC时S0/S1并不会交换.
164+
165+
## 5.3 Remembered Set
166+
一个对象和它内部所引用的对象可能不在同一个Region中,那么当垃圾回收时,是否需要扫描整个堆内存才能完整地进行一次可达性分析?
167+
当然不是,每个Region都有一个Remembered Set,用于记录本区域中所有对象引用的对象所在的区域,从而在进行可达性分析时,只要在GC Roots中再加上Remembered Set即可防止对所有堆内存的遍历.
168+
## 5.4 G1垃圾收集过程
169+
170+
- 初始标记
171+
标记与GC Roots直接关联的对象,停止所有用户线程,只启动一条初始标记线程,这个过程很快.
172+
- 并发标记
173+
进行全面的可达性分析,开启一条并发标记线程与用户线程并行执行.这个过程比较长.
174+
- 最终标记
175+
标记出并发标记过程中用户线程新产生的垃圾.停止所有用户线程,并使用多条最终标记线程并行执行.
176+
- 筛选回收
177+
回收废弃的对象.此时也需要停止一切用户线程,并使用多条筛选回收线程并行执行.
178+
![这里写图片描述](http://upload-images.jianshu.io/upload_images/4685968-0ea2b3a18ecc561a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
179+
180+
S0/S1的功能由G1中的Survivor region来承载,通过GC日志可以观察到完整的垃圾回收过程如下,其中就有Survivor regions的区域从0个到1个
181+
![](https://upload-images.jianshu.io/upload_images/4685968-ad5f6b99b3de502e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
182+
红色标识的为G1中的四种region,都处于Heap中.
183+
G1执行时使用4个worker并发执行,在初始标记时,还是会触发STW,如第一步所示的Pause
184+
185+
186+
187+
188+
189+
190+
191+
192+
193+
194+
195+
196+
197+
198+
199+
200+
201+
202+
203+
204+
205+
206+
207+
208+
209+
210+
211+
212+
213+
214+
215+
216+
217+
218+
219+
220+
221+

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.