JVM(五) 生产环境内存溢出调优

1.gc配置参数

1.1 控制台打印gc日志

-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC(详细的gc信息)

1.2 输出gc日志到指定文件 -Xloggc:

(例如:  -Xloggc:C:\logs\gc.log)

1.3 Gc日志分块

-XX:-UseGCLogFileRotation
-XX:GCLogFileSize = 8M

1.4 指定最小堆内存 -Xms

(例如-Xms20M指定最小堆内存为20M)

1.5 指定最大堆内存 -Xmx

(例如-Xms20M指定最大堆内存为20M)

1.6 指定新生代内存大小 -Xmn

(例如-Xmn10M指定新生代内存为10M)

1.7 指定eden区在新生代的占比 -XX:SurvivorRatio=8

(eden比S0,S1区比例为8:1:1)

1.8元空间设置大小 -XX:MetaspaceSize

初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize

最大空间,默认是没有限制的。

1.9 指定创建的对象超过多少会直接创建在老年代 -XX:PretenureSizeThreshold

此参数只能在serial收集器和parnew收集器才有效

(比如 -XX:PretenureSizeThreshold=1M)

1.10 指定多大年龄的对象进入老年代 -XX:MaxTenuringThreshold

(比如 -XX:MaxTenuringThreshold=15 默认也是15次)

1.11 内存溢出时候打印堆内存快照 -XX:+HeapDumpOnOutOfMemoryError

-XX:+HeapDumpOnOutOfMemoryError

该配置会把快照保存在用户目录或者tomcat目录下,也可以通过 -XX:HeapDumpPath=/tmp/heapdump.dump来显示指定路径

1.12 使用serialGC收集器 -XX:+UseSerialGC  

1.13 使用ParNew收集器 -XX:+UseParNewGC

1.14使用cms收集器 -XX:+UseConcMarkSweepGC

该标志首先是激活CMS收集器。默认HotSpot JVM使用的是并行收集器。

启动CMS多线程执行

-XX:+CMSConcurrentMTEnabled

指定CMS启动线程个数

 -XX:ConcGCThreads

标志-XX:ConcGCThreads=<value>(例如:-XX:ConcGCThreads=4)

指定老年代内存达到多少的百分比进行垃圾收集

-XX:CMSInitiatingOccupancyFraction=70 和 -XX:+UseCMSInitiatingOccupancyOnly

执行多少次fullgc后执行一次full gc的标记压缩算法

默认参数场景是:-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0。这意味着每次full gc(标记清除)后,都会压缩

开启在CMS重新标记阶段之前的清除minor gc

-XX:+CMSScavengeBeforeRemark

2. GC日志详情

2.1 minor gc

1.178: [GC (Allocation Failure) [PSYoungGen: 32768K->2688K(37888K)] 32768K->2696K(123904K), 0.0048091 secs] [Times: user=0.05 sys=0.02, real=0.00 secs]

1.178: # 虚拟机启动以来的秒数
[GC (Allocation Failure)
  [PSYoungGen: 32768K
->2688K(37888K)] # gc类型:新生代gc前占用大小 -> 新生代gc后占用大小(新生代总容量)
  32768K->2696K(123904K), # 堆空间gc前占用大小 -> 堆空间gc后占用大小(堆空间总容量)
  0.0048091 secs #gc总耗时
] [
Times:
  user
=0.05 #用户态耗费时间
  sys=0.02, #内核态耗费时间
  real=0.00 secs #整个过程实际耗费时间
]
# user+sys是CPU时间,每个CPU core单独计算,所以这个时间可能会是real的好几倍。

2.2 full gc / major gc

 7.740: [Full GC (Metadata GC Threshold) [PSYoungGen: 6612K->0K(333824K)] [ParOldGen: 10378K->15906K(95744K)] 16990K->15906K(429568K), [Metaspace: 34026K->34026K(1079296K)], 0.1300535 secs] [Times: user=0.38 sys=0.00, real=0.13 secs] 

7.740: #虚拟机启动以来的秒数
[
Full GC (Metadata GC Threshold) #gc类型
[PSYoungGen: 6612K->0K(333824K)] # 新生代gc前占用大小 -> 新生代gc后占用大小(新生代总容量)
[ParOldGen: 10378K->15906K(95744K)] # 老年代代gc前占用大小 -> 老年代gc后占用大小(老年代总容量)
16990K->15906K(429568K), # 堆空间gc前占用大小 -> 堆空间gc后占用大小(堆空间总容量)
[Metaspace: 34026K->34026K(1079296K)], # 元空间gc前占用大小 -> 元空间gc后占用大小(元空间总容量)
0.1300535 secs #gc总耗时
]

[
Times:
  user=0.05 #用户态耗费时间
  sys=0.02, #内核态耗费时间
  real=0.00 secs #整个过程实际耗费时间
]
# user+sys是CPU时间,每个CPU core单独计算,所以这个时间可能会是real的好几倍。

3. 生产环境死锁定位

 在开始前,需要清除线程状态有哪些. 线程的状态有:new、runnable、running、waiting、timed_waiting、blocked、dead

 

在定位死锁的时候主要关注下面几个日志信息

deadlock:表示有死锁
waiting on condition:等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待
blocked:阻塞
waiting on monitor entry:在等待获取锁

in Object.wait():获取锁后又执行obj.wait()放弃锁

3.1 案例一

 3.1.1 来一段死锁代码

package com.kawa.xuduocloud.zuul;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: xuduocloud
 * @author: Brian Huang
 * @create: 2019-12-07 15
 **/
@RestController
public class JvmController {

    @GetMapping("/deadLock")
    public ResponseEntity<String> deadLock(){

        Object lockA = new Object();
        Object lockB = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                synchronized (lockA) {
                    System.out.println(name + " got lockA,  want LockB");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {

                        e.printStackTrace();
                    }
                    synchronized (lockB) {
                        System.out.println(name + " got lockB");
                        System.out.println(name + ": say Hello!");
                    }
                }
            }
        }, "thread-lock-A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {

                String name = Thread.currentThread().getName();
                synchronized (lockB) {
                    System.out.println(name + " got lockB, want LockA");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {

                        e.printStackTrace();
                    }
                    synchronized (lockA) {
                        System.out.println(name + " got lockA");
                        System.out.println(name + ": say Hello!");
                    }
                }

            }
        }, "thread-lock-B").start();
        return  new ResponseEntity<>("deadLock", HttpStatus.OK);
    }

}

3.1.2 jps 查看所有的Java进程及其pid

我这边启动是XuduocloudZuulApplication这个项目

 3.1.3 然后通过jstack <pid> >  <path> 导出jstack信息

$ jstack 18640 > C:\\Users\\LiangHuang\\Desktop\\lock.txt

打开lock.txt文件,搜索关键字“deadlock”,可以很清晰的看到锁与等待锁的信息

Found one Java-level deadlock:
=============================
"thread-lock-B":
  waiting to lock monitor 0x000000001e9975b8 (object 0x00000000e8cc87d8, a java.lang.Object),
  which is held by "thread-lock-A"
"thread-lock-A":
  waiting to lock monitor 0x0000000017e26338 (object 0x00000000e8cc87c8, a java.lang.Object),
  which is held by "thread-lock-B"

Java stack information for the threads listed above:
===================================================
"thread-lock-B":
    at com.kawa.xuduocloud.zuul.JvmController$2.run(JvmController.java:55)
    - waiting to lock <0x00000000e8cc87d8> (a java.lang.Object)
    - locked <0x00000000e8cc87c8> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:748)
"thread-lock-A":
    at com.kawa.xuduocloud.zuul.JvmController$1.run(JvmController.java:34)
    - waiting to lock <0x00000000e8cc87c8> (a java.lang.Object)
    - locked <0x00000000e8cc87d8> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

3.2 案例二

这个死锁在来自生产代码,spring容器启动死锁问题(DefaultSingletonBeanRegistry),上日志

Full thread dump OpenJDK 64-Bit Server VM (11.0.11+9-LTS mixed mode):

Threads class SMR info:
_java_thread_list=0x00007f1150000b60, length=19, elements={
0x00007f120c02b000, 0x00007f120c276800, 0x00007f120c27a800, 0x00007f120c28f800,
0x00007f120c291800, 0x00007f120c293800, 0x00007f120c295800, 0x00007f120c297800,
0x00007f120c35b000, 0x00007f120c61c800, 0x00007f120cb09800, 0x00007f117c002800,
0x00007f11bc001000, 0x00007f118089a000, 0x00007f11783d5800, 0x00007f118089f000,
0x00007f1180903800, 0x00007f1180999800, 0x00007f1180ac4000
}"restartedMain" #16 prio=5 os_prio=0 cpu=3434.32ms elapsed=1748.50s tid=0x00007f117c002800 nid=0x1270d waiting on condition  [0x00007f118b7ed000]
   java.lang.Thread.State: WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@11.0.11/Native Method)
    - parking to wait for  <0x0000000714d07ac8> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(java.base@11.0.11/LockSupport.java:194)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(java.base@11.0.11/AbstractQueuedSynchronizer.java:885)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(java.base@11.0.11/AbstractQueuedSynchronizer.java:1039)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@11.0.11/AbstractQueuedSynchronizer.java:1345)
    at java.util.concurrent.CountDownLatch.await(java.base@11.0.11/CountDownLatch.java:232)
    at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:87)
    at reactor.core.publisher.Flux.blockLast(Flux.java:2519)
    at org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter.lambda$onApplicationEvent$0(WeightCalculatorWebFilter.java:133)
    at org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter$$Lambda$562/0x000000080055f840.accept(Unknown Source)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.ifAvailable(DefaultListableBeanFactory.java:2035)
    at org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter.onApplicationEvent(WeightCalculatorWebFilter.java:133)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)
    at com.kawa.spbgateway.service.ScheduleRefreshRoute.refreshRoute(ScheduleRefreshRoute.java:46)
    - locked <0x000000070fa25868> (a com.kawa.spbgateway.service.ScheduleRefreshRoute)
    at com.kawa.spbgateway.service.ScheduleRefreshRoute.init(ScheduleRefreshRoute.java:34)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.11/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.11/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.11/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@11.0.11/Method.java:566)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$272/0x00000008002b2440.getObject(Unknown Source)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    - locked <0x000000070f8faae0> (a java.util.concurrent.ConcurrentHashMap)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    - locked <0x000000070f669138> (a java.lang.Object)
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:64)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332)
    at com.kawa.spbgateway.SpbGatewayApplication.main(SpbGatewayApplication.java:10)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.11/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.11/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.11/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@11.0.11/Method.java:566)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
"boundedElastic-1" #28 daemon prio=5 os_prio=0 cpu=46.83ms elapsed=1744.51s tid=0x00007f1180ac4000 nid=0x12726 waiting for monitor entry  [0x00007f11891b0000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:217)
    - waiting to lock <0x000000070f8faae0> (a java.util.concurrent.ConcurrentHashMap)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getIfAvailable(DefaultListableBeanFactory.java:2021)
    at org.springframework.cloud.gateway.support.ConfigurationService$$Lambda$558/0x000000080055e840.get(Unknown Source)
    at org.springframework.cloud.gateway.support.ConfigurationService$ConfigurableBuilder.doBind(ConfigurationService.java:150)
    at org.springframework.cloud.gateway.support.ConfigurationService$AbstractBuilder.bind(ConfigurationService.java:244)
    at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.lookup(RouteDefinitionRouteLocator.java:216)
    at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.combinePredicates(RouteDefinitionRouteLocator.java:189)
    at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.convertToRoute(RouteDefinitionRouteLocator.java:116)
    at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator$$Lambda$660/0x00000008005fcc40.apply(Unknown Source)
    at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:106)
    at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:543)
    at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:984)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127)
    at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:251)
    at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68)
    at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28)
    at java.util.concurrent.FutureTask.run(java.base@11.0.11/FutureTask.java:264)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(java.base@11.0.11/ScheduledThreadPoolExecutor.java:304)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.11/ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.11/ThreadPoolExecutor.java:628)
    at java.lang.Thread.run(java.base@11.0.11/Thread.java:829)

可以看到是所对象锁0x000000070f8faae0,DefaultSingletonBeanRegistry.java:234行锁住了,同时自己处于waiting状态的等待某个条件被唤醒,另外一个线程在DefaultSingletonBeanRegistry.java:217等地持有这个对象锁,翻看下代码,在getSingleton时锁住了

通过上面的堆栈可以看出:spring容器在初始化bean的时候,会对singletonObjects对象加锁;我自己在@PostConstruct方法中(下图左侧)开启了一个线程调用了ApplicationEventPublisher.publishEvent(new RefreshRoutesEvent(this))来刷新容器,最终也会触发spring加载另外的bean。第一个线程(初始化spring的main线程)还没有释放锁,第二个线程(自己开启的线程),也需要获取singletonObjects对象锁,这样就出现了死锁。表现出来的现象就是:spring容器卡在那里,不能完成所有bean的初始化。

spring初始化的时候,如果我们在spring提供的一些扩展点处(BeanFactoryAware/InitializingBean,RefreshEvent等),开启线程去获取或这创建,刷新bean很容易是的IOC容器出现死锁。因为spring初始化单例bean(大多数bean都是单例的)会加锁。如果初始化1个bean的时候,还没有释放锁,另一个线程再次触发spring加载bean,就会出现死锁。

知道了造成死锁的原因,修改起来就比较简单了,将左侧代码调整到右侧代码即可,即实现CommandLineRunner接口在,IOC初始化完毕后后执行run()方法在执行自己的刷新的逻辑

 其实定位线上死锁比较简单两个指令就可以可了  ==> jps+ jstack 

4. 生产环境CPU100%定位

 4.1 来一个cpu100%代码

4.2 通过top指令找到cpu占用率高的程序  top

可以看到pid为7977java进程占用最高

4.3 通过ps指令查找最展cpu的子线程  ps -mp pid -o THREAD,tid,time

可以看到tid为8072的子线程占用率最高

 4.4 通过jstack导出日志 分析日志   jstack pid >a.txt

查找方式最将刚才tid从十进制转为16进制   8072  => 1f88

在日志文件搜索关键字 ‘1f88’ 查找nid包含这个就是对应cpu100%的日志信息 , 如下

 生产环境cpu飙高三个指令就可以了  => top + ps + jstack

5.生产环境堆内存溢出定位

环境配置 -verbose:gc -XX:+PrintGCDetails -Xloggc:C:\Users\LiangHuang\Desktop\up\gc.log -XX:-UseGCLogFileRotation -XX:GCLogFileSize=5M -XX:HeapDumpPath=C:\Users\LiangHuang\Desktop\heapdump.dump -XX:+HeapDumpOnOutOfMemoryError

可以在oom时候生产快照,方便我们使用工具分析

5.1 内存溢出的定位

 5.1.1 上代码 内存溢出

5.1.2 jps查看程序pid

5.1.3 jstat 查看jvm内存使用情况 jstat -gctuil pid

5.1.4  oracle jdk 工具  jvisualvm.exe 分析快照

jvisualvm.exe导入dump文件

可以看到异常的线程,打开Show Threads 详细信息,搜索关键字“http-nio-82-exec-1”

5.2 内存泄漏的定位

 5.2.1 上代码内存泄漏

5.2.2 jps 查看程序pid

5.2.3 jstat查看内存情况 jstat -gcutil pid

 

 可以看到eden区和老年代  没有被回收,内存泄漏的导致不能被回收

5.2.4  oracle jdk 工具  jvisualvm.exe 分析快照

jvisualvm.exe导入dump文件

6.总结JVM

6.1. jvm常用的调优参数

-Xmx 堆内存最大值 -Xmx2g
-Xms 堆内存最小值 -Xms2g
-Xmn 新生代大小 默认时堆的1/3
-xss 线程栈空间大小 -Xss256k

6.2. jvm运行时数据区域由哪几个部分组成,各自作用

线程共享
堆: new出来的对象放在堆中,对象可能会栈上分配(内存逃逸分析)
元空间/方法区:class对象,常量,静态变量,运行时常量池

内存独占
栈:栈内部由栈帧组成,先进后出,栈帧(局部变量表,操作数栈,动态链接,返回地址)
PC寄存器(程序计数器):指向当前线程执行到多少行代码
本地方法栈: native修饰的方法

6.3. gc算法有哪些,gc收集器有哪些

gc算法==
分代算法
复制算法
标记清除
标记压缩
引用计数
可达性分析法

gc收集器==
young区 (Serial,ParNew,Parallel Scavenge)
old区(SerialOld,ParallelOld,CMS)
G1

6.4. GC Roots的对象有哪些

局部变量
静态变量
本地方法栈
静态常量 static final

6.5. 垃圾收集器各自优缺点

Serial:单线程收集 非单核服务器 stw比较长
Parnew: 多线程收集 多核线程比较快
PS: 可控吞吐量 (用户线程执行时间)/(用户线程执行时间+gc执行时间)
CMS: 初始标记(标记和gc roots相关的对象 有swt),
并发标记(标记被初始标记的对象关联的对象 和用户线程一起执行),
重新标记(新生代可达引用到老年代的对象,刚进入老年代的对象 stw),
并发清除 (和用户线程一起执行,清除老年代没有被标记的对象)

6.6.  full gc,minor gc,major gc,stw

minor gc新生代gc
major gc老年代gc
full gc= minor gc + major gc
stw: stop the word 停止其他所有的用户线程

6.7. jvm中一次完整的gc流程 ygc => fgc ,对象如何晋升到老年代

正常流程===
经过15次ygc(复制算法)晋升到老年代
大对象直接进入到老年代

非正常=== 
动态年龄 (s区
50%以上对象年龄 > s区平均年龄则进阶老年代,如果老年代空间不足则发生full gc) 空间担保 (s0或s1放不下这些对象,会进行于此空间担保(老年代剩余空间大于历代s区进阶的平均值则担保成功))如果担保 失败则发生full gc 元空间/方法区不足也会发生full gc,但不会被垃圾收集器回收

6.8.  内存泄漏判断

对象不能被gc回收就会导致内存泄漏
jstack 发生gull gc后,新生代和老年代的占用情况,如果占用的空间没有降低则可以判断放生内存泄漏
如果fgc放生频率远远高于ygc则发生了内存泄漏

6.9. 内存溢出判断

后台没写分页,大数据量,内存溢出报错后,对象会被回收,整个服务任然可用
内存泄漏导致的内存溢出,泄漏的对象不会被回收,知道我们的整个堆内存被占满,导致整个服务不可用

打印dump文件,分析快照,查找大对象

6.10.  java中的引用类型有哪些

强引用:Object o = new Objetc(); gc不会回收强引用对象
软引用:SoftReference 对内存占满时就会这里面的对象(这个一般用来做缓存)
弱引用:WearkReference 只能存在下一次gc之前 (minor gc,major gc发生就会被回收)
虚引用:Object o = new Object(); o = null; 提醒gc来回收这个对象
posted @ 2019-12-08 12:38  Brian_Huang  阅读(2263)  评论(0编辑  收藏  举报