jvm gc调试哥哥参数 有用 看4

1.什么情况下会发生栈内存溢出。

 

 


2.详解JVM内存模型
思路: 给面试官画一下JVM内存模型图,并描述每个模块的定义,作用,以及可能会存在的问题,如栈溢出等。

我的答案:

JVM内存结构

 

 

 kandao

3.JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。


4. JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

 

 


5.你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

 

 


6.JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存。
思路: 先画出Java内存模型图,结合例子volatile ,说明什么是重排序,内存屏障,最好能给面试官写 以下demo说明。

我的答案:

1)Java内存模型图:

 

Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中 保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。

2)指令重排序。

在这里,先看一段代码

public class PossibleReordering { static int x = 0, y = 0; static int a = 0, b = 0; public static void main(String[] args) throws InterruptedException { Thread one = new Thread(new Runnable() { public void run() { a = 1; x = b; } });Thread other = new Thread(new Runnable() { public void run() { b = 1; y = a; } }); one.start();other.start(); one.join();other.join(); System.out.println(“(” + x + “,” + y + “)”);}

1
2
运行结果可能为(1,0)、(0,1)或(1,1),也可能是(0,0)。因为,在实际运行时,代码指令可能并不是严格按照代码语句顺序执行的。大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简称OoOE或OOE)的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据时造成的等待3。通过乱序执行的技术,处理器可以大大提高执行效率。而这就是

指令重排。

 

7.简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。


双亲委派模型图:

 

8.说说你知道的几种主要的JVM参数

 

 


9.怎么打出线程栈信息。

 

 

 


10.强引用、软引用、弱引用、虚引用的区别?

 


11.内存模型以及分区,需要详细到每个区放什么。

 

 

 


12.堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。

 

 

 


13.简述 java 垃圾回收机制?

 

 


14.java 中垃圾收集的方法有哪些?

 

 

 


15.java 内存模型

 


16.java 类加载过程?

 

 

 

 

 

 

 


17. 简述 java 类加载机制?
虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的 java 类型。

18. 类加载器双亲委派模型机制?
当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,由父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。

19.什么是类加载器,类加载器有哪些?


20.简述 java 内存分配与回收策率以及 Minor GC 和 Major GC
对象优先在堆的 Eden 区分配。
大对象直接进入老年代.
长期存活的对象将直接进入老年代当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC.Minor Gc 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 Gc 的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代 GC的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 Minor GC 这样可以加快老年代的回收速度。

 

什么时候对象会进入老年代?
新创建出来的对象一开始都会停留在新生代中,但随着JVM的运行,有些存活的长的对象会慢慢的移动到老年代中。

根据对象年龄

JVM会给对象增加一个年龄(age)的计数器,对象每“熬过”一次GC,年龄就要+1,待对象到达设置的阈值(默认为15岁)就会被移移动到老年代,可通过-XX:MaxTenuringThreshold调整这个阈值。

 

一次Minor GC后,对象年龄就会+1,达到阈值的对象就移动到老年代,其他存活下来的对象会继续保留在新生代中。

动态年龄判断

根据对象年龄有另外一个策略也会让对象进入老年代,不用等待15次GC之后进入老年代,他的大致规则就是,假如当前放对象的Survivor,一批对象的总大小大于这块Survivor内存的50%,那么大于这批对象年龄的对象,就可以直接进入老年代了。

 

如图上的A、B、D、E这四个对象,假如Survivor 2是100m,如果A + B + D的内存大小超过50m,现在D的年龄是10,那E都会被移动到老年代。实际上这个计算逻辑是这样的:年龄1 + 年龄2 + 年龄n的多个对象总和超过Survivor区的50%,那就会把年龄n以上的对象都放入老年代。

大对象直接进入老年代

如果设置了
-XX:PretenureSizeThreshold这个参数,那么如果你要创建的对象大于这个参数的值,比如分配一个超大的字节数组,此时就直接把这个大对象放入到老年代,不会经过新生代。

这么做就可以避免大对象在新生代,屡次躲过GC,还得把他们来复制来复制去的,最后才进入老年代,这么大的对象来回复制,是很耗费时间的。

 

 

年轻代分三个区。一个 Eden 区,两个 Survivor 区(一般而言)。
大部分对象在 Eden 区中生成。当 Eden 区满时,还存活的对象将被复制到 Survivor 区
(两个中的一个),当这个 Survivor 区满时,此区的存活对象将被复制到另外一个
Survivor 区,当这个 Survivor 去也满了的时候,从第一个 Survivor 区复制过来的并且此时
还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor 的两个区是对称的,没
先后关系,所以同一个区中可能同时存在从 Eden 复制过来 对象,和从前一个 Survivor 复
制过来的对象,而复制到年老区的只有从第一个 Survivor 去过来的对象。而且,Survivor
 
 
 
1,监控 GC 的状态
使用各种 JVM 工具,查看当前日志,分析当前 JVM 参数设置,并且分析当前堆内存快照
和 gc 日志,根据实际的各区域内存划分和 GC 执行时间,觉得是否进行优化;
2,分析结果,判断是否需要优化
如果各项参数设置合理,系统没有超时日志出现,GC 频率不高,GC 耗时不高,那么没有
必要进行 GC 优化;如果 GC 时间超过 1-3 秒,或者频繁 GC,则必须优化;
注:如果满足下面的指标,则一般不需要进行 GC:
Minor GC 执行时间不到 50ms;
Minor GC 执行不频繁,约 10 秒一次;
Full GC 执行时间不到 1s;
Full GC 执行频率不算频繁,不低于 10 分钟 1 次;3,调整 GC 类型和内存分配
如果内存分配过大或过小,或者采用的 GC 收集器比较慢,则应该优先调整这些参数,并
且先找 1 台或几台机器进行 beta,然后比较优化过的机器和没有优化的机器的性能对比,
并有针对性的做出最后选择;
4,不断的分析和调整
通过不断的试验和试错,分析并找到最合适的参数
5,全面应用参数
如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。
学会阅读 GC 日志
以参数-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC 为例:
[DefNew: 1855K->1855K(1856K), 0.0000148 secs][Tenured: 2815K->4095K(4096K),
0.0134819 secs] 4671K
DefNew 指明了收集器类型,而且说明了收集发生在新生代。
1855K->1855K(1856K)表示,回收前 新生代占用 1855K,回收后占用 1855K,新生代大
小 1856K。
0.0000148 secs 表明新生代回收耗时。
Tenured 表明收集发生在老年代
2815K->4095K(4096K), 0.0134819 secs:含义同新生代
最后的 4671K 指明堆的大小。
收集器参数变为-XX:+UseParNewGC,日志变为:
[ParNew: 1856K->1856K(1856K), 0.0000107 secs][Tenured: 2890K->4095K(4096K),
0.0121148 secs]
收集器参数变为-XX:+ UseParallelGC 或 UseParallelOldGC,日志变为:
[PSYoungGen: 1024K->1022K(1536K)] [ParOldGen: 3783K->3782K(4096K)]
4807K->4804K(5632K),
CMS 收集器和 G1 收集器会有明显的相关字样
其他与 GC 相关的参数
调试跟踪之 打印简单的 GC 信息 参数: -verbose:gc, -XX:+PrintGC
打印详细的 GC 信息 -XX:+PrintGCDetails, +XX:+PrintGCTimeStamps
-Xlogger:logpath 设置 gc 的日志路,如: -Xlogger:log/gc.log, 将 gc.log 的路径设置到
当前目录的 log 目录下.
应用场景: 将 gc 的日志独立写入日志文件,将 GC 日志与系统业务日志进行了分离,方
便开发人员进行追踪分析。
-XX:+PrintHeapAtGC, 打印推信息
参数设置: -XX:+PrintHeapAtGC
应用场景: 获取 Heap 在每次垃圾回收前后的使用状况
-XX:+TraceClassLoading
参数方法: -XX:+TraceClassLoading
应用场景: 在系统控制台信息中看到 class 加载的过程和具体的 class 信息,可用以分析
类的加载顺序以及是否可进行精简操作。
-XX:+DisableExplicitGC 禁止在运行期显式地调用 System.gc()
-XX:-HeapDumpOnOutOfMemoryError 默认关闭,建议开启,在
java.lang.OutOfMemoryError 异常出现时,输出一个 dump.core 文件,记录当时的堆内存
快照。-XX:HeapDumpPath=./java_pid<pid>.hprof 默认是 java 进程启动位置,用来设置堆内存
快照的存储文件路径。
posted @ 2023-04-13 22:59  十一vs十一  阅读(25)  评论(0)    收藏  举报