27-内存知识

27-内存知识

基础概念

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

  • 硬盘数据,外设数据,玩了传输数据,要进CPU前,都要先进入内存
  • 临时存放,在断电后,内存内容就会丢失

内存的组成:内存地址+存储单元

存储单元-数据结构

堆栈

两种不同的数据结构

堆(heap)

一种经过排序的树型数据结构

存放程序的对象

链表

数组、列表:数据是有顺序的,从左到右,从0开始。如果要在列表中,插入一个数据,那么在插入位置之后的数据,都需要移动,删除列表中间某个数据,在位置之后的数据,也都要移动。

链表也是一种数组,它的每个数据存储的都是数据值+下一个元素的地址。

如果要在链表中,插入一个数据。插入位置「前一个元素」中的「下一个元素的地址」需要指向插入的数据的地址,「待插入的元素」记录「下一个元素的地址」。

查找一个数据时,需要从头开始读取数据,一个一个的比对,直到找到需要的数据才停止。这个过程会有大量的IO,所以读取数据速度并不快。

  • 二叉树

建立在链表的基础上的一种数据结构

二叉树左边存储的是小于自身数据,右边是存储大于自身数据

插入数据:因为是链表,插入速度也比较快

读取数据:因为数据已经做了二分,查找链路变短,IO就减少了,读取速度也变快

二叉树的不足:随着存储的数据量增大,二叉树会越来越大,那要查找某个数据的IO次数,也会非常多

  • B树「平衡二叉树」

不是一个简单的平衡二叉树,是一个立体的平衡二叉树

B树和平衡二叉树稍有不同的是B树属于多叉树又名平衡多路查找树(查找路径不只两个),数据库索引技术里大量使用者B树和B+树的数据结构

LIFO「Last In First Out」后进先出

  • 装入叫压入

  • 取出叫弹出

队列

FIFO「First In First Out」先进先出

  • 顺序队列
  • 循环队列

内存使用

一个程序运行起来,需要分配一块内存空间,无异常时,就在分配的空间中弹性伸缩存储

这个存储空间至少包含一块栈区,一块堆区,还会包括其他

  • 栈区:存放程序中的变量
  • 堆区:存放程序中的对象

JVM java虚拟机

程序计数器、java虚拟机栈、本地方法栈、方法区、堆内存

  • 程序计数器:记录持续执行字节码的行号指示器
  • java虚拟机栈:java方法执行时的内存模型
    • StackOverflowError:线程请求的栈深度大于虚拟机运行的最大深度
    • OutOfMemoryError:栈在动态扩展时,无法申请到足够的内存空间
    • 内存泄漏:程序运行时,申请的内存空间使用完了,不及时释放,导致可申请的内存空间越来越少。可以使用的内存空间越来越少。
  • 方法区:共享内存区域,存储已被虚拟机加载的数据
  • 栈内存:存储局部变量,变量有一定的作用域,离开作用域,空间就会被释放,所以更新速度快,生命周期短
  • 堆内存:存储数组和对象,new出来的都存堆里,如果数据消失,实体不会马上释放

OOM会导致整个内存条空间全被使用吗? 不会!只会消耗该程序申请的空间,不会消耗内存条全部空间

堆内存

  • 新生代=Eden(存放JVM刚分配的对象) + Survivor1 + Survivor2 (两个空间一样大,Eden中未被GC的对象,会在这两个区间来回拷贝,默认拷贝超过15次,就移入年老代)
  • Tenured 年老代
  • Perm 永久代(元空间)

内存空间的释放

GC资源回收

需要有GC,但是频率要合理,不能过高

怎么判断是可回收

  • 是否可达
  • 是否存活

判断哪些可被回收

  • 不要的、不能被回收:新生代、年老代
  • 拷贝算法:把新生代变为年老代

什么时候回收

  • 分配的空间不足,才会执行回收
  • 定时回收

怎么回收

垃圾回收算法:新生代-复制算法「清理Eden,将存活的复制到Survivor」,年老代-标记整理算法「先标记,再整理」

资源回收

只有在讲「堆」的时候,才会说资源回收。本地方法栈、程序计数器、虚拟机栈这些是不需要进行垃圾回收的

Java的内存回收机制

内存空间中垃圾回收的工作由垃圾回收器「Garbage Collecot,GC」完成。它的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。

参数含义

-Xms:初始堆大小
-Xmx:最大堆空间
-Xmn:设置新生代大小
-XX:SurivivorRatio:新生代eden空间,from空间,to空间的比例关系
-XX:PermSize:方法区初始大小
-XX:MaxPermSize:方法区最大值
-XX:MetaspaceSize:元空间GC阈值
-XX:MaxMetaspaceSize:最大元空间大小
-Xss:栈大小
-XX:MaxDirectMemorySize:直接内存大小,默认为最大堆空间

查看内存

1
2
3
4
root@zx:~# free -h
total used free shared buff/cache available
Mem: 3.8Gi 414Mi 293Mi 2.0Mi 3.2Gi 3.2Gi
Swap: 0B 0B 0B

Mem:物理内存

  • total合计
  • used已被用
  • free未使用
  • shared共享
  • buff/cache缓冲区、缓存
    • buff:对原始磁盘块(操作系统与磁盘交流的最小单位)的临时存储
    • cache:从磁盘读取文件的页缓存
  • available新进程可分配=free+可回收的

Swap:交换分区

一种虚拟内存,由磁盘虚拟化而来,存在于内存和磁盘之间,因为磁盘和内存之间速度存在差异

1
2
3
4
5
6
7
8
9
10
top - 14:51:35 up 169 days,  4:55,  1 user,  load average: 0.01, 0.02, 0.00
Tasks: 108 total, 1 running, 107 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.2 us, 0.5 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3936.1 total, 294.0 free, 414.6 used, 3227.6 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 3266.4 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
479183 root 10 -10 128.7m 37.5m 14.5m S 2.3 1.0 487:05.64 AliYunDun
672280 root 20 0 59.3m 53.2m 5.9m S 1.0 1.4 139:43.55 gunicorn
479138 root 10 -10 21.8m 5.7m 4.9m S 0.3 0.1 27:41.60 AliYunDunUpdate

VIRT 虚拟内存使用量 = Swap + RES

RES 物理内存使用量+未换出的虚拟内存大小 = CODE + DATA

SHR 共享内存使用量

Swap 虚拟内存中被换出的大小

CODE 代码占用的物理内存大小

DATA 代码之外的部分占用的物理内存大小

%MEM 使用的物理内存占总内存的比率

内存分析

jmap

命令:jmap [options] pid

-dump:生成java堆栈的快照信息
-heap:显示java堆详细信息,使用那种回收机制,参数配置,分代情况
-histo:显示堆中对象统计信息,包括类,实例数量

1
2
3
4
jmap -F -dump:format=b,file=jvmpertest110901.bin 3636
format=b 格式为二进制
file 输出到什么文件,文件格式.bin
3636 进程pid

这个命令,执行时间很长,生成的文件也很大

arthas

阿里巴巴开源的java诊断工具,实现了jvm自带的几乎所有诊断功能

安装

1
curl -O https://arthas.aliyun.com/arthas-boot.jar

工具上手

1
java -jar arthas-boot.jar

内存泄漏抓包

  • dashboard
  • heapdump

jvm分析

输出gc日志

jvm的启动参数中加入

1
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplicationsStopedTime

启动后输出:GC概要信息,详细信息,gc时间,gc造成的应用暂停时间

jcosole

jdk自带的内存分析工具,有图形界面,可以查看jvm内存信息,线程信息,类加载信息,MBean信息

1
jconsole.sh pid

jstat

jdk自带的分析gc工具,参数很多

1
jstat -gcutil pid 10000 间隔10000毫秒显示一次gc信息
 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
您的支持将鼓励我继续创作!