内存分析

内存分析

一、内存简介

1、介绍:内存(memory),又叫主存,是CPU与其他设备沟通的桥梁,主要用来临时存放数据,配合CPU工作,协调CPU的处理速度

  1.1 内存的组成:内存地址+内存空间

    1.1.1 内存空间大小是有差异的,这个差异,就让我们出现不同大小空间存放不 同的数据

    1.1.2 比较小的数据类型: int、字符串、float ----栈

    1.1.3 比较大的数据类型: 方法、对象、类 ----堆

 

2、列表:是一种链表数据结构

 

3、链表:首先它也是一种数组,只是它的每一个数据存储的是数值+下一个元素的地址。如果在一个链表中插入一个数据,插入位置前一个元素中下一个元素的地址,指向 性插入的数据的地址,被插入的元素记录的下一个元素地址,数据本身不用移动,所以 要快很多。但是,相对应的读取的速度会变慢。

 

4、内存空间中的数据类型

  4.1 存在堆,栈两种数据类型

  4.2 栈stack: 压栈 弹出 LIFO(Last In First Out) 后进先出,代码中变量一般都放在栈里

  4.3 队列:FIFO 先进先出

  4.4 堆heap:是一种二叉树

    4.4.1 二叉树本身也是一个链表,数据与数据之间链接在一起

    4.4.2 二叉树是从顶点开始,左边的 小于顶点数据,右边的是大于顶点数据

    4.4.3 代码中的 对象、方法、类等等复杂的就都会放在堆里

 

5、内存结构图

  5.1 jvm(Java Virtual Machine java虚拟机)的典型数据:程序计数器、java虚拟机栈、本地方法栈、方法区、堆内存

    5.1.1 程序计数器:记录持续执行字节码的行号指示器

    5.1.2 java虚拟机栈:java方法执行时的内存模型

      5.1.2.1 StackOverflowError:线程请求的栈深度大于虚拟机运行的最大深 度

      5.1.2.2 OutOfMemoryError:栈在动态扩展时,无法申请到足够的内存空 间 内存溢出

    5.1.3 方法区:共享内存区域,存储已被虚拟机加载的数据

  5.2 内存泄漏:申请了一段内存空间,不释放,导致可用内存空间越来越小

  5.3 内存溢出:当可用的内存空间越来越少,当申请使用的内存空间比剩余的内存空间要大,导致申请不到足够的内存空间,这个时候就会产生内存溢出,出现内存泄漏一段时间就会出现内存溢出

 

6、堆内存划分

 

  6.1 新生代New: 昙花一现,朝生夕死的对象

    6.1.1 E区 + from区(Su1) + to区(Su2) surivivor E:F:T = 8:1:1

    6.1.2 Eden:存放JVM刚分配的对象

    6.1.3 回收 Eden区的对象,使用 copy算法

    6.1.4 Survivor:两个空间一样大,Eden中未被GC的对象,会在这两个区间来回copy,默认拷贝超过15次,就被移入Tenured 老年代

  6.2 老年代Tenured: 大对象 or 多次被GC后还在的对象(顽固份子)

  6.3 永久代(元空间)Perm: 类信息、常量、静态变量.....

 

7、GC回收

  7.1 哪些会被回收:引用计数法(被引用的计数等于0,回收),可达性算 法(没有引用链,回收)

  7.2 什么时候回收:分配的空间不足时回收,定时回收

  7.3 怎么回收:新生代-复制算法(清理Eden,将存活的复制到Survivor),老年代-标记整理算法(先标记,再整理)

  7.4 结论:新生代的资源回收YGC时间短,老年代的资源回收FGC时间要长

    7.4.1 GC资源回收,会导致卡顿,但是我们又需要有gc资源回收,来回收内存空间,让内存空间复用。

    7.4.2 我们需要在资源回收的同时,控制资源回收造成的卡顿时间,是卡顿时间达到最小

       7.4.2.1 假设执行一次YGC需要10mm,执行一次FGC需要100mm;如果定时1秒钟1次,1分钟60次ygc+fgc=60 *110 = 6600mm;如果定时1秒钟1次,10次YGC,才执行1次 FGC,1分钟10 *60 + 100*6 = 1200mm;如果定时1秒钟1次,10次FGC,才执行1次 YGC,1分钟60 * 100 + 6*10 = 6060

       7.4.2.2 所以,在实际工作中需要控制YGC的执行频率高于FGC的频率

    7.4.3 所以,新生代和老年代的空间配比,是可以影响我们的性能的。新生代 & 老年代 的空间配比是与项目有关系的。这个配比, 需要不断进行性能测试调优,才能找出相对比较合适的配比。

 

参数 含义
-Xms 初始堆大小
-Xmx 最大堆空间
-Xmn 设置新生代大小
-XX:SurivivorRatio 新生代eden空间、from空间、to空间的比例关系 后面直接跟数字的话,比例就是x:1:1
-XX:PermSize 方法区初始大小
-XX:MaxPermSize 方法区最大值
-XX:MetaspaceSize 元空间GC阈值
-XX:MaxMetaspaceSize 最大元空间大小
-Xss 栈大小
-XX:MaxDirectMemorySize 直接内存大小,默认为最大堆空间

   7.5 获取GC信息:可以在日志中打印GC信息,然后,分析GC日志;也可以用jsat来监控查看gc状态

    7.5.1 打印日志:在堆栈配置文件中,添加-XX:+PrintGC - XX:+PrintGCDetails -XX:+PrintGCTimeStamps - XX:+PrintGCApplicationStoppedTime -Xloggc:gc.log,启动后输出GC概要信息,详细信息,GC时间,GC造成的应用暂停时间;–Xloggc:gc.log 是把 gc日志打印到一个文件中,而不是写到我们项目日志中;日志路径:tomcat的bin文件夹中 gc.log文件

    7.5.2 gc.log:[GC (Allocation Failure) [PSYoungGen: 70272K->6645K(71680K)] 83927K->25135K(92160K), 0.1182240 secs] [Times: user=0.01 sys=0.15, real=0.12 secs] 5.392: [Full GC (Ergonomics) [PSYoungGen: 6645K->2896K(71680K)] [ParOldGen: 18490K->20274K(36352K)] 25135K->23171K(108032K), [Metaspace: 16387K->16387K(1064960K)], 0.1576823 secs] [Times: user=0.08 sys=0.23, real=0.16 secs]

  7.6 jconsole:jdk自带,但是要在图像界面系统中运行

    7.6.1 使用场景:在我们讲CPU-us使用率高的时候,我们要定位线程栈,Windows,我们可以直接使用 jconsole命令 > 线程

  7.7 jstat 打印gc统计信息

    7.7.1 jstat -gcutil 1768 1000 间隔1秒把进程号为1768的java进程的gc 信息打印出来

-gcutil option
Summary of garbage collection statistics.
S0: Survivor space 0 utilization as a percentage of the space's
current capacity. Survivor0 利用率占空间当前容量的百分比
S1: Survivor space 1 utilization as a percentage of the space's
current capacity.
E: Eden space utilization as a percentage of the space's
current capacity.
O: Old space utilization as a percentage of the space's current
capacity.
M: Metaspace utilization as a percentage of the space's current
capacity.
CCS: Compressed class space utilization as a percentage. 类空间的
回收比例
YGC: Number of young generation GC events.
YGCT: Young generation garbage collection time.
FGC: Number of full GC events.
FGCT: Full garbage collection time.
GCT: Total garbage collection time.

  7.8 分析gc日志:http://gceasy.io/

    7.8.1 我们项目中,有发现大量 ygc和fgc,jstat分析发现我们的fgc非常多,fgc的时间 也很长,说明,我们新生代和老年代的空间比例需要调整小,调小新生代空间之后,那么,我的老年代的空间就会增大,那么我的FGC 的频率就会降低,那么卡顿时间就会降低,接口平均响应时间就会降低, 接口的TPS就会升高。

  

8、项目实战

  8.1 环境

    8.1.1 jdk1.8

    8.1.2 tomcat:bin文件夹下 catalina.sh catalina.bat,JAVA_OPTS="-Xms256m -Xmx256m -Xmn128m"

    8.1.3 JvmPertest.war

  8.2 运行接口:http://ip:8080/JvmPertest/pertest1 用多个线程数,持续运行一段时间

  8.3 看到错误 java.lang.OutOfMemoryError: Java heap space

  8.4 OOM内存溢出,会消耗机器的所有内存吗?

    8.4.1 不会, 项目在启动时,分配了一定的内存大小,OOM只要超过分配的内存大小,就会报OOM问题,并不会占用机器所有的内存

  8.5 OOM分析:

    8.5.1 jmap: 是 jdk自带的一个java内存dump工具,这个工具可以dump java堆信息到hprof文件中,命令:jmap -dump:live,format=b,file=heap.bin <进程id>,由于速度太慢,一般不使用

    8.5.2 arthas: 阿里开源 java内存诊断工具

      8.5.2.1 安装命令:curl -O https://arthas.aliyun.com/arthas-boot.jar

      8.5.2.2 启动命令:java -jar arthas-boot.jar 启动arthas 先必须启动至少1个java进程,第一次启动,会自动下文件,需要一些时间

      8.5.2.3 help帮助命令;dashboard 面板;thread 线程信息;heapdump 获取堆栈;

    8.5.3 下载dump文件,用MemoryAnalyzer(MAT)进行分析,也可以把文件下载下来给到开发进行分析。

 

posted @ 2022-07-05 00:15  无名。。。  阅读(294)  评论(0编辑  收藏  举报