2019尚硅谷互联网大厂高频重点面试题(第2季)5 JVM,GC Roots,常用参数,4大查看参数,堆 栈 新生代 老年代 元空间 GC细节,JVM调优实战,新到老需次数和比例

JVM

内存结构

Class files——》 类装载器子系统Class loader

——》

运行时数据区(Runtime Data Area)

  • 方法区Method Area (GC 的作用域,就在这两个)
  • 堆heap

下面这3个,线程私有,几乎不存在 垃圾回收

  • Java栈Java stack
  • 本地方法栈 Native Method Stack
  • 程序计数器 Program Counter Register

本地方法库——》

  • 本地方法接口Native Interface

执行引擎ExecutionEngine

类加载,堆,jvm

类装载器子系统Class loader

  • 启动类加载器/ 根加载器 。bootstrap
  • 扩展类 加载器
  • 应用类加载器
  • 继承ClassLoader 自定义加载器

双亲委派机制,沙箱安全机制。

  • 启动类(根)加载器 BootStrap
    //只有 扩展类 + 根加载器 都没有的时候,才会执行 应用程序加载器的。

1.类加载器收到类加载的请求
2.将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器
3.启动加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载

  • 总之就是往上面的类加载器 加载,找不到才往下面的 类加载器加载。
  • 最终都没有找到:class Not Found

堆:

  • Eden
    survivor 幸存者0区,1区
    survivor

  • 养老区

  • jdk1.7 之前叫:永久代

  • java8 叫做元空间。

    • 因为:Oracle 收购了 san 和 bea公司。整合2套jvm

Java堆从GC的角度还可以细分为:新生代(Eden区、From Survivor 区和To survivor凶)和老年代。

  • 三种jvm
  • Sun公司的HotSpot ,平时用
  • BEA公司的JRockit
  • IBM公司的J9 JVM
    • j9vm JIT

4种垃圾回收算法

  • 分代收集算法
引用计数
  • 有对象引用+1,没对象引用 -1,到0为止 回收。

1.引用计数法
(应用:微软的COM/ActionScrip3/Python…)

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

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

复制算法:新生代 默认堆1/3
  • 设置年轻代大小 NewSize。新生代 默认堆1/3。老年代默认2/3

  • 新生代:中 Eden占 8/10,From 和 to 各占 1/10

  • 年轻代

  • 复制之后,有交换,谁空谁是to

  • 没有内存碎片,浪费空间,大对象复制耗时。

  • Survivor 0区,叫 From区。幸存者0区。

MinorGC的过程(复制-→>清空-→>互换)

1:eden~SurvivorErom复制到SurvivorTo,年龄+1
首先,当Eden区满的时候会触发第一次GC,把还活着的对象拷贝到SurvivorFrom区,当Eden区再次触发GC的时候会扫描Eden区和From区域,对这两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域(如果有对象的年龄已经达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1

:清空eden、SurvivorErom
然后,清空Eden和SurvivorFrom中的对象,也即复制之后有交换,谁空谁是to

3: Survivor To和 SurvivorFrom互换
最后,SurvivorTo和SurvivorErom互换,原SurvivorTo成为下一次GC时的SurvivorFrom区。部分对象会在From和To区域中复制来复制去,如此交换15次(由VM参数MaxIenuring.Threshold.决定,这个参数默认是15),最终如果还是存活,就存入到老年代

Survivor
英
/səˈvaɪvə(r)/
n.
(灾难性事故中的)幸存者,生还者,幸存物;能在艰苦环境中生存的人,挺过困难者;
标记清除
  • 先标记,在清除
  • 节约了内存空间,产生了内存碎片。

垃圾收集算法——标记清除法(Mark-Sweep)

算法分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些对象。形如:

回收前

  • 标记出:
    • 可回收
      存活对象
      未使用

回收后

  • 上面所有 可回收的区域,变为未使用。
标记压缩
  • 标记清除 和 压缩,用于 老年代。

  • 标记整理

1.标记(Mark):
与标记-清除一样。

2.压缩(Compact):
再次扫描,并往一端滑动存活对象。

没有内存碎片,可以利用bump
需要移动对象的成本

boot2.0 用了 Undertow

JVMGC +SpringBoot微服务的生产部署和调参优化

SpringBoot2.0后将tomcat换Undertow吞吐量增强

1. GC Roots

常见的垃圾回收算法

1.JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots

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

判断一个对象是否可以被回收
  • 对象指向null,或 没人引用。

要进行垃圾回收,如何判断一个对象是否可以被回收?

引用计数法

Java中,引用和对象是有关联的。如果要操作对象则必须用引用进行。
因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,给对象中添加一个引用计数器,每当有一个地方引用它,计数器值加1 ,
每当有一个引用失效时,计数器值减1。
任何时刻计数器值为零的对象就是不可能再被使用的,那么这个对象就是可回收对象。
那为什么主流的Java虚拟机里面都没有选用这种算法呢﹖其中最主要的原因是它限难解决对象之间相互循环引用的问题。

该算法存在但目前无人用了,解决不掉循环引用的问题,了解即可。

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

为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。

跟踪(Tracing)

·复制(Copying)
标记-清除(Mark-Sweep)
标记-压缩(Mark-Compact)
Mark-Sweep(-Compact)

  • 都要用:GC引用遍历

所谓“GC roots”或者说tracing GC的“根集合”就是一组必须活跃的引用

  • GC roots 作为起点,进行链路的 自顶向下的 扫描和访问。没扫描到的,是垃圾。

    • 根 相当于 Linux /

    • 不是从 GC root起点开始,各种依赖,都当做垃圾。

      • 引用 不可达对象。
      • 狗没有主人了,穿着毛衣(和狗依赖),也被认为 流浪狗。
    • GC root Set 是一个集合。

    • GC root 根指向了,对象A,A指向了 对象A1,A2,代表 引用可到达对象。

      • GC root 没有从 根指向,称为引用不可达对象
    • 就是 从 根 到 所有的管理,没有引用到这个对象,将被垃圾回收。

基本思路就是通过一系列名为**”GC Roots”的对象作为起始点,从这个被称为GCRoots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时**,则说明此对象不可用(将会被垃圾回收)。也即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可到达的)对象就被判定为存活;没有被遍历到的就自然被判定为死亡。

可以作为GC roots对象
  • 是个 set 集合

虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)

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

方法区中常量引用的对象。

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

  • 比如 线程的 stat0(),是 Native方法

  • 局部变量

  • 静态属性

  • 常量

  • Native方法

public class GCRootDemo {
    private byte[] b = new byte[1024 * 1024];

    //假如又引用了 另一个对象
    //静态只有一份,全部实例公用。java7是方法区叫永久代,java8叫元空间。
    //2 静态属性
    // private static GCRootDemo2 t2;

    //常量引用
    //3 常量
    //private static GCRootDemo2 t2= new GCRootDemo2();

    public static void m1() {
        //1 本地变量
        GCRootDemo r = new GCRootDemo();
        System.gc();
        System.out.println("第一次GC完成");
    }

    public static void main(String[] args) {
        m1();
    }
}

2.如何查看JVM系统默认值

你说你做过JVM调优和参数配置,请问如何查看JVM系统默认值

  • MateSpace
JVM的参数类型
标配参数
-version
-help
java -showversion
X参数(了解)
-Xint
解释执行 interpreted

-Xcomp
第一次使用就编译成本地代码

-Xmixed
混合模式,先编译在执行。 compiled

java -Xint -version
XX参数

—Boolean类型

-XX:+或者–某个属性值
+表示开启
-表示关闭

  • 是否打印GC收集细节
-XX:-PrintGCDetails
-XX:+PrintGCDetails
  • 是否使用串行垃圾回收器
-XX:-UseSerialGC
-XX:+UseSerialGC

如何查看一个正在运行中的java程序,它的某个jvm参数是否开启?具体值是多少?

  • jps 后台进程
  • jinfo 正在运行的info信息
jps -l #查看出 pid

jinfo -flag PrintGCDetails xxxx
-XX:-PrintGCDetails # - 代表未开启

#使用Idea 加上这个参数,再次测试。是开启的
-XX:+PrintGCDetails

—Kv设值类型

jinfo举例,如何查看当前运行程序的配置

-XX:属性key=属性值value
  • 最大堆内存,元空间
  • 最大垃圾回收时间,
-XX:MetaspaceSize=128m
-XX:MaxTenuringThreshold=15 #最大期限阈值,年轻代 到老年代,要活过15次,用这个参数调整
jinfo -flag MetaspaceSize PID #查看元空间大小
-XX:Metaspacesize=21807104 #20.79M,我的也是。就是21M吧
# /1024 得出K,/1023 得出B

-XX:MetaspaceSize=1073741824 #改了1G后。除以2次1024,得1024M


jinfo -flag MaxTenuringThreshold 16888 
-XX:MaxTenuringThreshold=15
命令0:jsp 和 jinfo
  • 如何查看系统默认值
jps -l #查看出 pid

jinfo -flag PrintGCDetails xxxx

MetaspaceSize
MaxTenuringThreshold
  • jfnfo 初始化堆大小1/64
jinfo -flag 配置项 进程编号

InitialHeapSize

jinfo -flag InitialHeapSize 17428
-XX:InitialHeapSize=803209216 #766M。

jinfo -flag UseSerialGC 17428
-XX:-UseSerialGC #是否使用串行垃圾回收器

jinfo -flag MaxHeapSize 5108
-XX:MaxHeapSize=12847153152
  • 查看所有
jinfo -flags 17428

Non-default VM flags #根据机器配置,改动过的

-XX:InitialHeapSize=803209216 -XX:MaxHeapSize=12847153152
#初始化堆:766M * 64 = 48G,我内存。默认为1/64
#最大堆为:12G,默认为 1/4

# 新生代 多大。255M 
-XX:NewSize=267386880 
# 老年代 511M
-XX:OldSize=535822336
# 最大 新生区 为4084,4个G
XX:MaxNewSize=4282384384 
#元空间,默认21M,现在设置成了1G
-XX:MetaspaceSize=1073741824 

-Dfile.encoding=UTF-8


Attaching to process ID 17428, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=803209216 -XX:MaxHeapSize=12847153152 -XX:MaxNewSize=42
82384384 -XX:MetaspaceSize=1073741824 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=267386880 -XX:OldSize=535822336 -XX:+Use
CompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -
XX:+UseParallelGC

Command line:  -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:3397,suspend=y,server=n -XX:MetaspaceSize=1024m -ja
vaagent:C:\MySoft\ideaIU-2021.2.2.win\plugins\java\lib\rt\debugger-agent.jar -Dfile.encoding=UTF-8
-Xms和-Xmx 和 -Xss

两个经典参数:-Xms和-Xmx

-Xms

等价于-XX:InitialHeapSize

  • 初始化 堆内存
-Xmx10m
-XX:InitialHeapSize=1024m

等价于-XX:MaxHeapSize
-Xmx

  • 最大堆内存。
-Xss //初始的栈空间
java -XX:+PrintFlagsFinal -Xss128k 类名

ThreadStackSize : 线程栈的大小,jvm启动时由Xss指定。设置单个线程栈的大小,一般默认为512k~1024K
* -XX:+PrintFlagsFinal
* maxHeapSize 289406976 byte
* maxPermSize 85983232 byte
* threadStackSize 1024 byte

# 配置了1个G
-XX:ThreadStackSize=1024m
jinfo -flag ThreadStackSize 14960
-XX:ThreadStackSize=1073741824
Runtime.getRuntime().maxMemory();//使用-Xmx10m 调节。最大分配内存。默认为1/4。堆的最大值。

//初始的堆空间
Runtime.getRuntime().totalMemory();//使用-Xms5m调节。初始化内存分配大小。默认1/64

-Xms1024m -Xmx1024m -XX:+PrintGCDetails ///打印GC垃圾回收
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError //oom DUMP 堆dump在 内存溢出错误
命令1:PrintFlagsInitial 初始值
  • 第二种,查看参数盘点家底
-XX:+PrintFlagsInitial 
#PrintFlagsFinal举例,运行java命令的同时打印出参数
java -XX:+PrintFlagsInitial -version
java -XX:+PrintFlagsInitial #直接运行,就是这个命令
#Print Flags Init ial
Initial
英
/ɪˈnɪʃ(ə)l/
adj.
开始的,最初的;(字母)位于词首的
  • := false 说明被改过(JVM默认加载时 或 人为),不带: 说明没被改过
java -XX:+PrintFlagsInitial #打印出的太多了

[Global flags]
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
命令2:PrintFlagsFinal 修改以后
  • 查看和动态修改 PrintFlagsFinal
more HelloJc.java #windows 下的cat

-XX:+PrintFlagsFinal #这是改过以后的 主要查看修改更新
java -XX:+PrintFlagsFinal -version #这是查看。
uintx MetaspaceSize                             = 21807104                            {pd product}

# 加参数运行这个程序,变为了 512M
java -XX:+PrintFlagsFinal -XX:MetaspaceSize=512m HelloJc
 uintx MetaspaceSize                            := 536870912                           {pd product}
 
java -XX:+PrintFlagsFinal -Xss128m 类名。
# ThreadStackSize : 线程栈的大小,jvm启动时由Xss指定
命令3:PrintCommandLineFlags 默认垃圾回收。
-XX:+PrintCommandLineFlags #运行时设置参数 即可打印。

java -XX:+PrintCommandLineFlags -version

-XX:+UseParallelGC #4个GC算法,7大GC垃圾回收。就是这4种算法的实现。
#决定了,现在用的垃圾回收器,是哪个。默认为:并行GC。


-XX:InitialHeapSize=802858688 -XX:MaxHeapSize=12845739008 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndiv
idualAllocation -XX:+UseParallelGC
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
无用:java带包的文件运行
package com.example.demo.test;

public class HelloJc {
}
//1. 在这个包下 javac .\HelloJc.java
//2. java com.example.demo.test.HelloJc 。在 \src\main\java 下执行。当前文件夹下有 com 包

//PS:如果 类没有带包路径,只能在 盘符的根目录运行,请配置 C:\MySoft\jdk1.8.0_131\lib ,到 classpath ,要用到 dt.jar 和 tools.jar ,和 linux 的一样。


javac -d . ThreadDemo.java #这样编译会自动创建包结构
java com.xx.ThreadDemo

整理:盘点JVM家底4种方式整理

-Xms和-Xmx 和 -Xss 和 -Xmn
-Xmx10m
-XX:InitialHeapSize=1024m

-Xmx
-XX:MaxHeapSize

-Xss128k
-XX:ThreadStackSize=1024m


-Xmn #Young Gen 
NewSize
JVM 3种参数类型

标配参数

X参数(了解)

XX参数

  • Boolean类型
  • Kv设值类型
命令4 jsp 和 jinfo
打印gc 元空间 新到老需次数 初始化和最大堆 使用GC 初始栈
jinfo -flags xx #查看自己追加的参数。老师的可以,我的不行。

jps -l
jinfo -flag PrintGCDetails xx
-XX:-PrintGCDetails #未开启,把这个 换成+,即可开启。布尔类型

jinfo -flag MetaspaceSize xx
-XX:MetaspaceSize=128m
# 元空间,默认20.79M,现在设置成了1G
-XX:MetaspaceSize=1073741824


jinfo -flag MaxTenuringThreshold xx 
-XX:MaxTenuringThreshold=15

jinfo -flag InitialHeapSize xx
jinfo -flag MaxHeapSize xx
#初始化堆:766M * 64 = 48G,我内存。默认为1/64
-XX:InitialHeapSize=803209216
#最大堆为:12G,默认为 1/4
-XX:MaxHeapSize=12847153152

jinfo -flag UseSerialGC xx
-XX:-UseSerialGC #默认没开,这是序列化GC吧。默认为并行。布尔类型。如下
jinfo -flag UseParallelGC 9572
-XX:+UseParallelGC

jinfo -flag ThreadStackSize xx
堆dump
-XX:+HeapDumpOnOutOfMemoryError
新生代 老年代 最大新生代
jinfo -flags

# 新生代 老年代 多大。255M 和 511M
-XX:NewSize=267386880
-XX:OldSize=535822336

# 最大 新生区 为4084,4个G
-XX:MaxNewSize=4282384384 
命令1:PrintFlagsInitial 初始
java -XX:+PrintFlagsInitial -version
java -XX:+PrintFlagsInitial

initial
adj.
开始的,最初的;(字母)位于词首的

flag
英
/flæɡ/
旗帜;国旗;信号旗,标志旗;菖蒲,鸢尾;铺路用的厚石板(多为矩形或正方形);
v.
给……做标记;示意……停下来,挥手示停;(裁判向场内)丢旗判罚;疲乏,热情衰减;引起对……的注意
** 命令2:PrintFlagsFinal 修改以后
java -XX:+PrintFlagsFinal -version

java -XX:+PrintFlagsFinal -XX:MetaspaceSize=512m HelloJc
java -XX:+PrintFlagsFinal -Xss128m HelloJc

#编译器后 指定,是打印下参数
-XX:+PrintFlagsFinal
命令3:PrintCommandLineFlags 默认垃圾回收。
  • 记得 带 + 号
java -XX:+PrintCommandLineFlags -version

Print Command Line Flags

常用参数

堆 初始最大 最大直接内存 栈 年轻代 元空间和最大元空间 GC细节
新生区 养老区 比例,新到老需次数
总览:SurvivorRatio
Runtime.getRuntime().maxMemory();//使用-Xmx10m 调节。默认为1/4。堆的最大值。显示为字节。 /1024/1024 为MB

Runtime.getRuntime().totalMemory();//使用-Xms5m调节。默认1/64。初始的堆空间
-Xms
初始大小内存,默认为物理内存1/64等价于 -XX:InitialHeapSize

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

-XX:MaxDirectMemorySize=5m #这是直接内存,默认为 1/4 少一点。我的为:
sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024 + "MB"  10891.0MB

-Xss
设置单个线程栈的大小,一般默认为512k~1024K。线程私有的。栈管运行,堆管存储。
等价于-xx:ThreadStackSize
-Xss128k 配置后,显示的是128,如果配置1m,显示1024。

jinfo -flag ThreadStackSize 13412 
-XX:ThreadStackSize=0 #默认显示0,是出厂默认值

. Linux/x64(64-bit): 1024 KB
. OS X(64-bit): 1024 KB
. Oracle Solaris/x64(64-bit): 1024 KB
. Windows: The default value depends on virtual memory

-Xmn
-设置年轻代大小 NewSize。新生代 默认堆1/3。老年代默认2/3
新生代:中 Eden占 8/10,From 和 to 各占 1/10

-XX:MetaspaceSize
-设置元空间大小
-Xms10m -Xmx10m -XX:MetaspaceSize=1024m -XX:+PrintFlagsFinal
-XX:MaxMetaspaceSize=8m
元空间的本质和永久代类似,都是对JvM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:
元空间并不在虚拟机中,而是使用本地内存。
因此,默认情况下,元空间的大小仅受本地内存限制
# 元空间,默认20.79M,所以 必须配置


-XX:+PrintGCDetails
输出详细Gc收集日志信息
GC
Full GC

sur vi vor
-XX:SurvivorRatio
幸存0区 from 和 1区的 to 的比例。参考复制算法
设置新生代中eden和 so/s1空间的比例
默认
-XX:SurvivorRatio=8,Eden:S0:S1=8:1:1
假如
-XX:SurvivorRatio=4, Eden:So:S1 =4:1:1。4x+1x+1x=总共的。
SurvivorRatio值就是设置eden区的比例占多少,so/s1相同

- 设置年轻代大小 NewSize。新生代 默认堆1/3。老年代默认2/3
- 新生代:中 Eden占 8/10,From 和 to 各占 1/10


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


-XX:MaxTenuringThreshold
#最大养老区到的 吞吐量,
#设置垃圾最大年龄。经过多少次 年轻代,才去 老年代。默认15
# 必须设置为 0 - 15 之间。

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

Survivor
英
/səˈvaɪvə(r)
n.
(灾难性事故中的)幸存者,生还者,幸存物;能在艰苦环境中生存的人,挺过困难者;

tenuring
英
/ˈtenjə(r)/
n.
(土地的)居住权,保有权;(尤指大学教师的)终身职位,长期聘用;(尤指重要政治职务的)任期,任职
v.
授予……终身职位(尤指教师、讲师职位)

threshold
英
/ˈθreʃhəʊld
n.
门槛,门口;阈,界,起始点;开端,起点,入门;机场跑道入口,跑道头


ratio
英
/ˈreɪʃiəʊ
n.
比率,比例
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:SurvivorRatio=4

# 如下: 总共10M,新生区分到了 3M多(1/3)。from区 和 to区 * 4 = 伊甸园区。4x+1x+1x=总共的。

# 如下:默认 老年代是 新生代的 2倍多。新生代占3.3,老年代占6.6
---------------
Heap
 def new generation   total 2880K, used 1325K
  eden space 2368K,  34% used
  from space 512K, 100% used
  to   space 512K,   0% used 
 tenured generation   total 6848K, used 343K 
调优实战 *设置元空间
parallel
英
/ˈpærəlel/

adj.
平行的;相似的,同时发生的;(计算机)并行的;并联的
n.
(人或事物的)相似的手法,共同点;相似的人(或物);(地球的)纬线,纬圈;(印刷)平行符号
v.
与……相似;与……同时发生;与……并行;与……相当,比得上
adv.
与……平行
配置后:
-Xms128m -Xmx4096m -Xss1024k -XX:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC
#堆(初始和最大),栈,元空间,打印极简(PrintCommandLineFlags),打印GC细节,使用什么GC
# 1GC,2打印,4设置。我认为最重要的,就是设置元空间

默认 -XX:+PrintCommandLineFlags
-XX:InitialHeapSize=802858688 #默认堆为 内存1/64
-XX:MaxHeapSize=12845739008 #默认最大堆为 内存1/4
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC  #默认使用 并行的JC,比串行的强。


程序运行时:PrintCommandLineFlags
-XX:InitialHeapSize=134217728  #初始化堆128m
-XX:MaxHeapSize=4294967296  #最大堆 4G
-XX:MetaspaceSize=536870912 #元空间512m
-XX:+PrintCommandLineFlags #打印用什么gc等
-XX:+PrintGCDetails  #打印详细参数
-XX:ThreadStackSize=1024 #栈空间1024K
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseSerialGC #使用串行垃圾回收器。默认是并行。


#设置上面所有参数 运行结束:PrintGCDetails
Heap
 def new generation   total 39296K, used 6303K [0x00, 0x000, 0x000000) #堆总共38.375M??
  eden space 34944K,  18% used [0x000, 027d38, 0x0000000)
  from space 4352K,   0% used [0x0000, 0x00000, 0x00000000)
  to   space 4352K,   0% used [0x00660000, 0x0000, 0x00000000)
 tenured generation   total 87424K, used 0K [0x0050000, 0x0000000, 0x000)
   the space 87424K,   0% used [0x000000, 0x000000, 0x050200, 0x0b0000)
 Metaspace       used 3406K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 369K, capacity 392K, committed 512K, reserved 1048576K
 
 
# 只设置这一个参数:PrintGCDetails
Heap
 PSYoungGen      total 228864K, used 19660K [0x00000006c0c00000, 0x00000006d0b00000, 0x00000007c0000000)
  eden space 196608K, 10% used [0x00000006c0c00000,0x00000006c1f33390,0x00000006ccc00000)
  from space 32256K, 0% used [0x00000006ceb80000,0x00000006ceb80000,0x00000006d0b00000)
  to   space 32256K, 0% used [0x00000006ccc00000,0x00000006ccc00000,0x00000006ceb80000)
 ParOldGen       total 523264K, used 0K [0x00000004c2400000, 0x00000004e2300000, 0x00000006c0c00000)
  object space 523264K, 0% used [0x00000004c2400000,0x00000004c2400000,0x00000004e2300000)
 Metaspace       used 3406K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 369K, capacity 392K, committed 512K, reserved 1048576K
堆溢出oom
  • GC 在新生区
  • Full GC 在养老区
-Xms10m -Xmx10m
        byte[] b = new byte[1024 * 1024 * 11];
        System.out.println("---------------");

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
[GC (Allocation Failure) [PSYoungGen: 2048K->504K(2560K)] 2048K->868K(9728K), 0.0006287 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

GC类型  PSYoungGen

#2048K->504K(2560K) 新生代占用1/3 2560K,养老区占用2/3 7168K
YoungGC前新生代内存占用
YoungGC后前新生代内存占用。
新生代总共大小

#2048K->868K(9728K) 这是总的
YoungGC前JVM堆内存占用
YoungGC后JVM堆内存使用
JVM堆总大小

YoungGC耗时 0.0007821 secs

YoungGC用户耗时  user=0.00
YoungGC系统耗时  sys=0.00
YoungGC实际耗时  real=0.00 secs


#老年代 都抗不住了,报oom
[Full GC (Allocation Failure) 
[PSYoungGen: 0K->0K(2560K)] 
[ParOldGen: 966K->950K(7168K)] 966K->950K(9728K), 
[Metaspace: 3397K->3397K(1056768K)], 
0.0061651 secs] 
[Times: user=0.00 sys=0.00, real=0.01 secs] 

[名称:
GC前内存占用
GC后内存占用
(该区内存)
元空间

在Java8中,永久代已经被移除,被一个称为元空间的区域所取代。元空间的本质和永久代类似。

元空间(Java8)与永久代(Java7)之间最大的区别在于:
永久带使用的JvM的堆内存,但是java8以后的元空间并不在虚拟机中而是使用本机物理内存。

因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入native memory,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而由系统的实际可用空间来控制。

JVM面试题

3.你平时工作用过的VM常用基本配置参数有哪些?

4.强引用、软引用、弱引用、虚引用分别是什么?

  • 强引用(Strong Reference)、
  • 软引用(Soft Reference)、
  • 弱引用(Weak Reference)、
  • 虚引用(Phantom Reference)4 种

Java中默认声明的就是强引用

Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收

//软引用
SoftReference<byte[]> sr = new SoftReference<>(buff);

WeakReference<byte[]> sr = new WeakReference<>(buff);

5.请谈谈你对oOM的认识

  • -java.lang.StackOverflowError
  • -java.lang.OutOfMemoryError: Java heap space
  • -java.lang.OutOfMemoryError: GC overhead limit exceeded 超过开销限额
  • java.lang.OutOfMemoryError: Direct buffer memory 直接缓冲存储器
  • -java.lang.OutOfMemoryError: Metaspace 元空间
  • java.lang.OutOfMemoryError: unable to create new native thread
  • java.lang.OutOfMemoryError: Requested array size exceeds VM limit

6.GC回收算法和垃圾收集器的关系?另外,串行收集/并行收集/并发收集/STW是什么?

7.怎么查看服务器默认的垃圾收集器是那个?
生产上你是如何配置垃圾收集器的?谈谈你的理解?

8.G1垃圾收集器21

9.生产环境服务器变慢,诊断思路和性能评估谈谈?

10.假如生产环境出现CPu占用过高,请谈谈你的分析思路和定位(13

11.对于JDK自带的Jvm监控和性能分析工具用过哪些?一般你是怎么用的?

  • jconsole.exe
  • jps,类似Linux系统里面的Ps -ef命令
  • jinfo
  • jmap
  • jstat
  • jstack

12.JVM的字节码指令接触过吗?

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值