【面試(自己看)】二、JVM(1)之 GC

7 篇文章 0 订阅

1. JVM体系结构概览

在这里插入图片描述

Java栈, 本地方法栈, 程序计数器 都是随线程的生命周期创建销毁的.

标红的部分, 方法区和堆 才是 GC 的作用域

1.1 常见的垃圾回收算法

  • 引用计数
  • 复制
  • 标记清除
  • 标记整理
1.1.1 引用计数法

通俗讲就是 有对象引用 +1 ,没有对象引用就 -1
在这里插入图片描述

对象C 就没有被其它对象引用,此时计数为0, 会被GC回收

缺点

  • 每次对象赋值时均要维护引用计数器, 且计数器本身也有一定的消耗;
  • 较难处理循环引用

JVM的实现一般不采用这种方式

1.1.2 复制算法

在这里插入图片描述

1.1.3 标记清除

在这里插入图片描述
优点

对象的标记没有大面积的去复制节约了内存空间

缺点

会产生 内存碎片

1.1.4 标记整理

在这里插入图片描述

既不浪费空间也不产生碎片, 但是耗时间

在这里插入图片描述

2 大厂面试题

第一题

【大厂原题】
JVM垃圾回收的时候如何确定垃圾? 是否知道什么是GC Roots

1.1 什么是垃圾?

简单的说就是内存中已经不再被使用到的空间就是垃圾;

1.2 如何判断一个对象是否可以被回收?

  • 引用计数法
  • GC Roots(枚举根节点做可达性分析)
1.2.1 引用计数法

最简单的办法就是通过引用计数来判断一个对象是否可以回收. 简单说,给对象中添加一个引用计数器, 每当有一个地方引用它, 计数器加1. 每当有一个引用失效时, 计数器值减1;

任何时刻计数器值为零的对象就是不可能再被使用的, 那么这个对象就是可回收对象;

由于它很难解决对象之间的相互循环引用问题, 该算法目前不被使用

1.2.2 GC Roots

枚举根节点做可达性分析(根搜索路径算法)

为了解决引用计数法的循环引用问题, Java使用了可达性分析的方法;
在这里插入图片描述
所谓"GC roots" 或者说 tracing GC 的"根集合" 就是一组必须活跃的引用

基本思路就是通过一系列名为"GC Roots"的对象作为起始点, 从这个被称为 GC Roots的对象开始向下搜索, 如果一个对象到 GC Roots没有任何引用链相连时, 则说明此对象不可用.
也就是说我们需要给定一个集合的引用作为根触发,通过引用关系 遍历对象图, 能被遍历到的(可达到的)对象就被判定为存活, 没有被遍历到的就自然被判定为死亡;

1.2.2.1 Java中可以作为 GCRoots的对象

虚拟机栈(栈帧中的局部变量区,也叫局部变量表)中引用的对象

方法区中的类静态属性引用的对象

方法区中常量引用的对象

本地方法栈中 JNI(Native方法)引用的对象

第二题

【大厂原题】
你说你做过JVM调优和参数配置, 请问如何盘点查看JVM系统默认值

2.1 JVM参数类型

  • 标配参数
  • x参数(了解)
  • xx参数(重点)

2.1.1 标配参数

	-version
	-help
	java -showversion

2.1.2 x参数

-Xint 解释执行
-Xcomp 第一次使用就编译成本地代码
-Xmixed 混合模式

在这里插入图片描述

2.1.3 xx参数

  • Boolean类型
  • KV设置类型
2.1.3.1 Boolean类型的 XX参数

公式
-XX:+或者-某个属性值

+表示开启, -表示关闭

Case

  • 是否打印GC收集细节
    -XX:-PrintGCDetails

此时:后面为-表示关闭

-XX:+PrintGCDetails

此时表示开启

  • 是否使用串行垃圾回收器
    -XX:-UserSerialGC

此时表示不使用

-XX:+UserSerialGC

此时表示使用

2.1.3.2 KV设置类型的 XX参数

公式
```-XX:属性key=属性value``

Case
-XX:MetaspaceSize=128m

元空间的的值

-XX:MaxTenuringThreshold=15

新生代需要多少次的交换才能升级为老年代

2.1.4 jinfo命令 查看当前运行程序的配置

jinfo -flags 进程号可以查看当前进程下所有的XX型程序配置

配合 jps 命令使用

  1. jps 查看当前项目的进程编号
  2. jinfo -flag 属性名 查看值大小

我们查看一把元空间初始值
在这里插入图片描述
然后我们修改一下元空间初始值,再次进行查看
在这里插入图片描述

2.1.5 题外话

两个经典参数-Xms-Xmx这你如何解释?
答:
-Xms等价于-XX:initialHeapSize(初始化的堆内存)
-Xmx等价于-XX:MaxHeapSize(最大的堆内存)

2.2 查看JVM默认值

我们前面讲了, 可以通过jinfo -flags 进程号在程序启动后进行查看

下面看两个正规一些的
-XX:+PrintFlagsInitial

主要查看初始默认参数

公式
java -XX:+PrintFlagsInitial -version

主要查看初始默认参数, 加上-version 会打印出JDK版本信息

-XX:+printFlagsFinal

主要查看修改和更新的内容

公式
java -XX:+printFlagsFinal -version

主要查看修改和更新的内容, 加上 -version 会打印出JDK版本信息

我们通过以上命令查看结果的时候,有些KV类型的参数 会是:=这表示是我们自己修改过的参数值

-XX:+PrintCommandLineFlags

打印命令行参数
在这里插入图片描述

2.2.1 如何在运行中的程序内 修改参数配置,以栈空间大小举例

格式:
java -XX:+PrintFlagsFinal 参数名=value 运行的Java类名
在这里插入图片描述

第三题

【大厂原题】
你平时工作中用过的JVM常用基本配置参数有哪些?
答(精简版):
在这里插入图片描述
具体讲解
-Xms

初始大小内寸, 默认为物理内存1/64
等价于-XX:InitialHeapSize

-Xmx

最大分配内存, 默认为物理内存1/4
等价于-XX:MaxHeapSize

-Xss

设置单个线程栈的大小, 一般默认为512k-1024k(Linux系统下)
等价于-XX:ThreadStackSize

-Xmn

设置年轻代大小(一般不用调,默认1/3堆空间)

-XX:MetaspaceSize

设置元空间大小
元空间是对JVM规范中方法区的实现,元空间并不在虚拟机中,而是使用本地内存;
因此元空间的大小仅受本地内存限制

元空间默认值大概在20m左右,但是为了避免项目中不断创建对象导致出现OOM的异常,我们都会习惯性的将元空间调大值1024m

-XX:+PrintGCDetails

输出GC的详细日志信息

-XX:SurvivorRatio

设置新生代中 eden和s0/s1空间的比例
默认
-XX:SurvivorRatio=8
Eden:s0:s1=8:1:1
假如
-XX:SurvivorRatio=4
SurvivorRatio值就是设置eden区的比例占40%, s0/s1占剩下的平均分各20%

-XX:NewRatio

配置年轻代与老年代在堆结构的占比
默认
-XX:NewRatio=2新生代栈1,老年代占2. 年轻代占整个堆的 1/3
假如
-XX:NewRatio=4表示新生代占1, 老年代占4,年轻代占整个堆的 1/5
NewRatio值就是设置老年代的占比,剩下的 1 给新生代

-XX:MaxTenuringThreshold

设置垃圾最大年龄,默认为15(最大15)
如果设置为0的话,则年轻代对象不经过Survivor区, 直接进入老年代. 对于老年代比较多的应用,可以提高效率. 如果将此值设置为一个较大值, 则年轻代对象会在 Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加在年轻代即被回收的概率.

第四题

【大厂原题】
强引用,软引用,弱引用,虚引用分别是什么?

答:
强引用,不管该对象有没有,JVM都不会对其进行垃圾回收;
软引用,内存够用, 不会被回收;内存不够用,为避免OOM,会被回收
弱引用,只要对象没有被引用,就会回收
虚引用,在任何情况下都可能被垃圾回收器回收

4.1 引用的类图

在这里插入图片描述

4.1.1 强引用

强引用(默认支持)
当内存不足, JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收

强引用是我们最常见的普通对象引用, 只要还有强引用指向一个对象, 就能表名对象还活着, 垃圾收集器不会碰这种对象.
在Java中最常见的就是强引用,把一个对象赋给一个引用变量, 这个引用变量就是一个强引用. 当一个对象被强引用变量引用时, 它处于可达状态. 它是不可能被垃圾回收机制回收的, 即使该对象以后永远都不会背用到JVM也不会回收.
因此强引用是造成Java内存泄漏的主要原因之一

4.1.2 软引用

SoftReference
软引用是一种相对强引用弱化了一些的引用, 可以让对象豁免一些垃圾收集.

对于只有软引用的对象来说:
当系统内存充足时它 不会 被回收
当系统内存不足时它 会 被回收

软引用通常用在堆内存敏感的程序中,比如高速缓存就用到软引用

4.1.3 弱引用

WeakReference
通俗讲,只要GC,弱引用就会被回收;
它比软引用的生存期更短;

对于只有弱引用的对象来说,只要垃圾回收机制一运行. 不管JVM的内存空间是否足够, 都会回收该对象占用的内存;(前提是对象以不再被引用)

Map<String,SoftReference<BitMap>> imageCache = new HashMap<String,SoftReference<BitMap>>();

你知道弱引用的话,能谈谈WeakHashMap吗?
通俗点讲就是 只要 WeakHashMap对象中的 key,不再被引用, 只要GC,该内存就会立马被回收

4.1.4 虚引用

PhantomReference
顾名思义, 就是形同虚设, 与其它几种引用都不同, 虚引用并不会决定对象的生命周期;

如果一个对象仅持有虚引用, 那么它就和没有任何引用一样, 在任何时候都可能被垃圾回收器回收, 他不能单独使用也不能通过它访问对象. 虚引用必须和引用队列ReferenceQueue联合使用, 当某些对象不再被引用(弱或虚), 会被先放置到ReferenceQueue中,再真正被销毁

虚引用的主要作用是跟踪对象被垃圾回收的状态. 仅仅是提供了一种确保对象被finalize以后, 做某些事情的机制

PhantomReferenceget方法总是返回null, 因此无法访问对应的引用对象. 其意义在于说明一个对象已经进入 finalization 阶段, 可以被 gc 回收, 用来实现比 finalzation 机制更灵活的回收操作;

设置虚引用关联的唯一目的, 就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理

Java技术,允许使用finalize()方法在垃圾收集器将对象从内存中清楚出去之前做必要的清理工作

4.2 软引用和弱引用的使用场景

假如一个应用需要读取大量的本地读片:

  • 如果每次读取图片都从硬盘读取则会严重影响性能
  • 如果一次性全部加载到内存中有可能造成内存溢出;

此时使用软引用可以解决这个问题:

思路: 用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效的避免了OOM的问题;

第五题

【大厂原题】
谈谈你对OOM的认识
关于OOM的相关错误

//以下为Java虚拟机错误
java.lang.StackOverflowError 深度的方法调用(递归调用,方法过多),把栈空间给撑爆了

java.lang.OutOfMemoryError:Java heap space 堆内存空间不足

java.lang.OutOfMemoryError:GC overhead limit exceeded 
/**GC overhead limit exceeded 
GC回收时间过长会抛出以上错误
过长的定义是: 超过98%的时间用来做GC并且回收了不到2%的堆内存
连续多次GC都只回收了不到2%的极端情况下才会抛出. 加入不抛出 GC overhead limit错误会发生什么情况呢?
那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行, 这样就形成恶心循环
CPU 使用率一直是100% 而GC却没有任何成果
*/

java.lang.OutOfMemoryError:Direct buffer memory
/** 直接内存撑爆
导致原因:
写NIO程序经常用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的I/O方式
他可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作
这样能在一些场景中显著提高性能, 因为避免了在Java堆和Native堆中来回复制数据;

ByteBuffer.allocate(capability) 第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢
ByteBuffer.allocateDirect(capability) 第二种方式是分配OS(操作系统)本地内存, 不属于GC管辖范围, 由于不需要内存拷贝所以速度相对较快;

但是如果不断分配本地内存, 堆内存很少使用,那么JVM就不需要执行GC,  DirectByteBuffer对象们就不会被回收, 这时候堆内存充足, 但本地内存可能可能已经用光了,再次尝试分配本地内存就会出现OOM
*/

java.lang.OutOfMemoryError:unable to create new native thread
/** 无法创建更多本地线程
高并发请求服务器时,经常出现该异常
准确讲该native thread异常与对应的平台有关

导致原因:
1. 你的应用创建了太多线程了,一个应用进程创建多个线程,超过系统承载极限
2. 你的服务器并不允许你的应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,你的应用超过这个数量,就会报java.lang.OutOfMemoryError:unable to create new native thread

解决办法:
3. 想办法降低你应用程序创建线程的数量,分析应用是否真的需要创建这么多线程,如果不是,改代码将线程数降到最低
4. 对于有的应用,确实需要创建很多线程,远超过linux系统的默认值,可以通过修改linux服务器配置,扩大默认限制;
*/

java.lang.OutOfMemoryError:Metaspace
/**元空间
Java 8及以后使用Metaspace来替换永久代
Metaspace是方法区在HotSpot中的实现, 它与持久代最大的区别在于:Metaspace并不在虚拟机内存中而是使用本地内存,也即在java8中, classe metadata被存储在叫做Metaspace的native memory

元空间存放一下信息:
虚拟机加载的类信息
常量池
静态变量
即时编译后的代码

不断生成类往元空间灌,类占据的空间总是会超过Metaspace指定的空间大小的
*/

第六题

【大厂原题】
GC垃圾回收算法和垃圾收集器的关系是什么?

6.1 GC算法

GC算法(引用计数/复制/标记清除/标记整理)是内存回收的方法论, 垃圾收集器就是算法的落地实现

6.2 垃圾收集器

目前没有完美的收集器出现, 更加没有万能的收集器,只是针对具体应用最合适的收集器,进行分代收集;

6.2.1 4种主要垃圾收集器

在这里插入图片描述

Serial 和 Parallel 都属于 STW 类型的垃圾收集器

  • Serial(UseSerialGC) 串行
    它为单线程环境设计且只使用一个线程进行垃圾回收, 会暂停所有的用户线程. 所以不适合服务器环境;

  • Parallel(UseParallelGC) 并行
    多个垃圾收集线程并行工作, 此时用户线程是暂停的, 适用于科学计算/大数据处理首台处理等弱交互场景;

  • CMS(UseConcMarkSweepGC) 并发
    用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行),不需要停顿用户线程. 互联网用户多用它,适用对响应时间有要求的场景(强交互的场景)

  • G1(UseG1GC) G1

  • UseParNewGC 并行

新生代所用垃圾收集器

  • UseParallelOldGC 并行

老年代所有垃圾收集器

第七题

【大厂原题】
怎么查看服务器默认的垃圾收集器是哪个?生产上如何配置垃圾收集器的?谈谈你对垃圾收集器的理解.

7.1 怎么查看服务器默认的垃圾收集器是哪个?

**通过配置参数 -XX:+PrintCommandLineFlags``查看初始命令行参数`** 如:java --XX:+PrintCommandLineFlags```
在这里插入图片描述

可见初始的时候,JVM默认用的是并行垃圾收集器

7.2 如何配置垃圾收集器

7.3 谈谈你对垃圾收集器的理解

7.3.1 七大垃圾收集器所用位置

在这里插入图片描述

Old Gen 中的 Serial MSC 已经在Java8 被去掉

在这里插入图片描述

7.3.2 约定参数说明

DefNew = Default New Generation
Tenured = Old
ParNew = Parallel New Generation
PSYoungGen = Parallel Scavenge
ParOldGen = Parallel Old Generation

7.3.3 新生代
  • 串行 GC(Serial)(Serial Copying)
    一句话:一个单线程的收集器,在进行垃圾收集时候,必须暂停其它所有的工作线程直到它收集结束;
    在这里插入图片描述
    它是最古老,最稳定以及效率最高的收集器,只使用一个线程去回收但其在垃圾收集过程中可能会产生较长的停顿(STOP-THE_WORLD状态). 虽然在收集垃圾过程中需要暂停所有其它的工作线程,但是它简单高效,对于限定单个CPU环境来说,没有线程交互的开销可以获得最高的单线程垃圾收集效率,因此 Serial垃圾收集器依然是java虚拟机运行在Client模式下默认的新生代垃圾收集器

    如果通过java -XX:+UseSerialGC将新生代默认垃圾收集器设置为Serial串行垃圾收集器,那么老年代的默认垃圾收集器就是与之对应的 Serial Old(MSC); 此时新生代使用复制算法, 老年代使用标记整理算法;

  • 并行 GC(ParNew)
    一句话:使用多线程进行垃圾回收, 在垃圾收集时, 会Stop-The_world暂停其他所有的工作线程直到其它收集结束;
    在这里插入图片描述
    ParNew收集器其实就是Serial收集器新生代的并行多线程版本, 最常见的应用场景是配合老年代的CMS GC工作, 其余的行为和Serial收集器完全一样. ParNew垃圾收集器在垃圾收集过程中同样也要暂停所有其它的工作线程. 它是很多java 虚拟机运行在Server模式下新生代的默认垃圾收集器

对应参数: -XX:+UserParNewGC

启用ParNew收集器,只影响新生代的收集,不影响老年代
开启上述参数后, 会使用: ParNew(Young区用) + Serial Old的收集器组合, 新生代使用复制算法, 老年代采用 标记-整理算法

但是, ParNew+Tenured这样的搭配, java8已经不再被推荐

  • 并行回收GC(Parallel)(Parallel Scavenge)
    Parallel Scavenge收集器类似ParNew也是一个新生代垃圾收集器,使用赋值算法, 也是一个并行的多线程的垃圾收集器, 俗称吞吐量优先收集器, 一句话,串行收集器在新生代和老年代的并行化;
    在这里插入图片描述
    它关注点重点是:
    可控制的吞吐量(Thoughput=运行用户代码时间/(运行用户代码时间+垃圾收集时间),也即比如程序运行100分钟, 垃圾收集时间1分钟,吞吐量就是99%). 高吞吐量意味着高效利用CPU的时间, 它多用于在后台运算而不需要太多交互的任务;

自适应调节策略也是ParallelScavenge收集器与ParNew收集器的一个重要区别.(自使用调节策略:虚拟机会根据当前系统的运行情况手机性能监控信息, 动态调整这些整数以提供最合适的停顿时间(-XX:maxGCPauseMillis)或最大的吞吐量)

JVM参数:-XX:+UseParallelGC-XX:+UseParallelOldGC(可互相激活) 使用Parallel Scanvenge收集器

7.3.4 老年代
  • 串行GC(Serial Old)/(Serial MSC)
    老年代的串行垃圾收集器,java8已经不再使用;

  • 并行GC(Parallel Old)

  • 并发标记清除GC(CMS)
    CMS收集器(Concurrent Mark Sweep:并发标记清除) 是一种以获取最短回收停顿时间为目标的收集器.
    适合应用在互联网站或者B/S系统的服务器上, 这类应用尤其重视服务器的响应速度, 希望系统停顿时间最短.
    CMS非常适合堆内存大,CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器.
    在这里插入图片描述
    上图并发标记的4部过程

    • 初始标记(CMS initial mark)

      只是标记一下 GC Roots 能直接关联的对象, 速度很快,但是仍然需要暂停所有的工作线程

    • 并发标记(CMS concurrent mark)和用户线程一起

      进行GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程,主要标记过程,标记全部对象;

    • 重新标记(CMS remark)

      为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程;
      由于并发标记时, 用户线程仍然运行, 因此在正式清理前, 再做修正;

    • 并发清除(CMS concurrent sweep)和用户线程一起

      清楚GC Roots不可达对象, 和用户线程一起工作, 不需要暂停工作线程, 基于标记结果,直接清理对象;

      在这里插入图片描述

Concurrent Mark Sweep 并发标记清除, 并发收集低停顿,并发指的是与用户线程一起执行

开启该收集器的JVM参数:-XX:+UseConcMarkSweepGC开启该参数后会自动将-XX:+UseParNewGC打开

开启该参数后,使用ParNew(Young区)+CMS(Old区用)+Serial Old的收集器组合, Serial Old将作为CMS出错后的后被收集器

优缺点
优点: 并发收集低停顿
缺点:并发执行,对CPU资源压力大; 采用的标记清除算法会导致大量碎片;


问题延伸
如何选择合适的垃圾收集器?

  • 单CPU或小内存,单机程序 xx:UseSerialGC
  • 多CPU,需要最大吞吐量,如后台计算型应用XX:UseParallelGC或者XX:UseParallelOldGC
  • 多CPU追求低停顿时间,需快速响应如互联网应用-XX:UseConcMarkSweepGC
    在这里插入图片描述

第八题

【大厂原题】
G1垃圾收集器

8.1 G1垃圾收集器是什么

G1(Garbage-First)收集器,是一款面向服务端应用的收集器,应用在多处理器和大容量内存环境中,在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求. 它还具备以下特性:

  • 像CMS收集器一样,能与应用程序线程并发执行;
  • 整理空闲空间更快
  • 需要更多的时间来预测GC停顿时间
  • 不希望牺牲大量的吞吐性能
  • 不需要更大的Java Heap

G1收集器的设计目标就是取代CMS收集器,相比CMS,它:

  • 是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片;
  • 其Stop The World(STW)更可控, G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间;

G1垃圾收集器,祛除了内存碎片问题,同时又保留CMS垃圾收集器低暂停时间的优点;逐步替换Java8以前的CMS收集器;

主要改变是 Eden, Survivor和Tenured等内存区域不再是连续的了,而是变成了一个个大小不一样的region. 每个region从1M到32M不等.一个region有可能属于Eden, Survivor或者Tenured内存区域;

8.2 G1底层原理

区域化内存划片Region,整体编为了一些列不连续的内存区域, 避免了全内存区的GC操作;

核心思想是将整个堆内存区域分成大小相同的子区域(Region),在JVM启动时会自动设置这鞋子区域的大小, 在堆的使用上,G1并不要求对象的存储一定是物理上连续的只要逻辑上连续即可, 每个分区也不会固定为某个代服务, 可以按需在年轻代和老年代之间切换. 启动时可以通过参数-XX:G1HeapRegionSize=n可指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为2048个分区

大小范围在1MB~32MB, 最多能设置2048个区域,也即能够支持的最大内存为:32MB * 2048 = 65536MB = 64G内存
在这里插入图片描述

G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器.
这些Region的一部分包含新生代, 新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间
这些Region的一部分包含老年代, G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作. 这就意味着在正常的处理过程中,G1完成了堆的压缩,这样也就不会有CMS内存碎片问题的存在了

在G1中,还有一种特殊的区域, 叫 Humongous(巨大的)区域,
如果一个对象占用的空间超过了分区容量50%以上, G1收集器就认为这是一个巨型对象. 这些巨型对象默认直接会被分配在老年代, 但是如果他是一个短期存在的举行对象, 就会对垃圾收集器造成负面影响.
为了解决这个问题, G1划分了一个Hugmongous区,他用来专门存放巨型对象.如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储. 为了能找到连续的H区,有时候不得不启动Full GC

8.3 回收步骤

在这里插入图片描述
在这里插入图片描述

8.4 4步过程

在这里插入图片描述

8.5 常用配置

//todo

后续补充

8.6 和CMS垃圾收集器比较

有两个优势

  • G1不会产生内存碎片;
  • 是可以精确控制停顿. 该收集器是把整个堆(新生代,老年代)划分成多个固定大小的区域, 每次根据允许停顿的时间去收集垃圾最多的区域;

第九题

【大厂原题】
生产环境服务器变慢, 诊断思路和性能评估
变慢可能出现的方面(linux系统内诊断,你常用的linux命令)

  • 整机: top
    top -Hp
    在这里插入图片描述

uptime 可以的到 laod average结果

  • CPU:vmstat
    vmstat -n 2 3 表示每2秒采样一次,共计3次
    在这里插入图片描述

  • 内存:free
    在这里插入图片描述

  • 硬盘:df
    !](https://img-blog.csdnimg.cn/20200329205919205.png)

  • 磁盘IO:iostat
    在这里插入图片描述

  • 网络IO:ifstat

第十题

【大厂原题】
假如生产环境出现CPU占用过高, 请谈谈分析思路和定位

结合Linux和JDK命令一块分析

  1. 先用top命令找出CPU占比最高的

  2. ps -ef或者jps进一步定位,得知是一个怎么样的一个后台程序给我们惹事

  3. 定位到具体的线程或者代码
    在这里插入图片描述

    -m 显示所有的线程
    -p pid进程使用cpu的时间
    -o 该参数后是用户自定义格式

  4. 将需要的线程ID转换为16进制格式(英文小写格式)

  5. jstack进程ID | grep tid(16进程线程ID小写英文)-A60

第十一题

【大厂原题】
对于JDK自带的JVM监控和性能分析工具用过哪些?一般是怎么用的?
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值