共计 11119 个字符,预计需要花费 28 分钟才能阅读完成。
1) 堆
运行时数据区域,所有类实例和数组的内存均从此处分配。Java 虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。
堆由两部分组成:
其中 eden+fromspace+tospace 也叫年轻代(young),old space 叫旧生代.
其中还有 S1,S0(在 JDK 的自带工具输出中会看到), 分别指的是 Survivor space, 存放每次垃圾回收后存活的对象.
Old Generation , 主要存放应用程序中生命周期长的存活对象
垃圾回收主要是对 Young Generation 块和 Old Generation 块内存进行回收,YG 用来放新产生的对象,经过几次回收还没回收掉的对象往 OG 中移动,
对 YG 进行垃圾回收又叫做 MinorGC,对 OG 垃圾回收叫 MajorGC,两块内存回收互不干涉
2) 非堆内存
JVM 具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
除了方法区外,Java 虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT 编译器需要内存来存储从 Java 虚拟机代码转换而来的本机代码,从而获得高性能。
Permanent Generation (图中的 Permanent Space)存放 JVM 自己的反射对象,比如类对象和方法对象
3) 回收算法和过程
JVM 采用一种分代回收 (generational collection) 的策略,用较高的频率对年轻的对象 (young generation) 进行扫描和回收,这种叫做 minor collection,而对老对象 (old generation) 的检查回收频率要低很多,称为 major collection。这样就不需要每次 GC 都将内存中所有对象都检查一遍。
当一个 URL 被访问时,内存申请过程 如下:
A. JVM 会试图为相关 Java 对象在 Eden 中初始化一块内存区域
B. 当 Eden 空间足够时,内存申请结束。否则到下一步
C. JVM 试图释放在 Eden 中所有不活跃的对象(这属于 1 或更高级的垃圾回收), 释放后若 Eden 空间仍然不足以放入新对象,则试图将部分 Eden 中活跃对象放入 Survivor 区
D. Survivor 区被用来作为 Eden 及 OLD 的中间交换区域,当 OLD 区空间足够时,Survivor 区的对象会被移到 Old 区,否则会被保留在 Survivor 区
E. 当 OLD 区空间不够时,JVM 会在 OLD 区进行完全的垃圾收集(0 级)
F. 完全垃圾收集后,若 Survivor 及 OLD 区仍然无法存放从 Eden 复制过来的部分对象,导致 JVM 无法在 Eden 区为新对象创建内存区域,则出现”out of memory 错误”
对象衰老的过程
young generation 的内存,由一块 Eden(伊甸园,有意思) 和两块 Survivor Space(1.4 文档中称为 semi-space)构成。新创建的对象的内存都分配自 eden。两块 Survivor Space 总有会一块是空闲的,用作 copying collection 的目标空间。Minor collection 的过程就是将 eden 和在用 survivor space 中的活对象 copy 到空闲 survivor space 中。所谓 survivor,也就是大部分对象在伊甸园出生后,根本活不过一次 GC。对象在 young generation 里经历了一定次数的 minor collection 后,年纪大了,就会被移到 old generation 中,称为 tenuring。(是否仅当 survivor space 不足的时候才会将老对象 tenuring? 目前资料中没有找到描述)
剩余内存空间不足会触发 GC,如 eden 空间不够了就要进行 minor collection,old generation 空间不够要进行 major collection,permanent generation 空间不足会引发 full GC。
4 接下来这部分讲解的是 TOMCAT 或者其他服务器出现如下错误时的分析:
1、首先是:java.lang.OutOfMemoryError: Java heap space
解释:
Heap size 设置
JVM 堆的设置是指 java 程序运行过程中 JVM 可以调配使用的内存空间的设置.JVM 在启动的时候会自动设置 Heap size 的值,其初始空间 (即 -Xms) 是物理内存的 1 /64,最大空间 (-Xmx) 是物理内存的 1 /4。可以利用 JVM 提供的 -Xmn -Xms -Xmx 等选项可进行设置。Heap size 的大小是 Young Generation 和 Tenured Generaion 之和。
提示:在 JVM 中如果 98%的时间是用于 GC 且可用的 Heap size 不足 2%的时候将抛出此异常信息。
提示:Heap Size 最大不要超过可用物理内存的 80%,一般的要将 -Xms 和 -Xmx 选项设置为相同,而 -Xmn 为 1 /4 的 -Xmx 值。
解决方法:
手动设置 Heap size
修改 TOMCAT_HOME/bin/catalina.bat,在“echo“Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:
Java 代码
set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m
set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m
或修改 catalina.sh
在“echo“Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:
JAVA_OPTS=”$JAVA_OPTS -server -Xms800m -Xmx800m -XX:MaxNewSize=256m”
2、其次是:java.lang.OutOfMemoryError: PermGen space
原因:
PermGen space 的全称是 Permanent Generation space, 是指内存的永久保存区域,这块内存主要是被 JVM 存放 Class 和 Meta 信息的,Class 在被 Loader 时就会被放到 PermGen space 中,它和存放类实例 (Instance) 的 Heap 区域不同,GC(Garbage Collection)不会在主程序运行期对 PermGen space 进行清理,所以如果你的应用中有很 CLASS 的话, 就很可能出现 PermGen space 错误,这种错误常见在 web 服务器对 JSP 进行 pre compile 的时候。如果你的 WEB APP 下都用了大量的第三方 jar, 其大小超过了 jvm 默认的大小 (4M) 那么就会产生此错误信息了。
解决方法:
1. 手动设置 MaxPermSize 大小
修改 TOMCAT_HOME/bin/catalina.bat(Linux 下为 catalina.sh),在 Java 代码
“echo“Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:
set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m
“echo“Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:
set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m
catalina.sh 下为:
Java 代码
JAVA_OPTS=”$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m”
JAVA_OPTS=”$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m”
JVM 的默认设置
**堆**(heap)(News Generation 和 Old Generaion 之和)的设置
初始分配的内存由 -Xms 指定,默认是物理内存的 1 /64 但小于 1G。
最大分配的内存由 -Xmx 指定,默认是物理内存的 1 /4 但小于 1G。
默认空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制,可以由 -XX:MinHeapFreeRatio= 指定。
默认空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制,可以由 -XX:MaxHeapFreeRatio= 指定。
服务器一般设置 -Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小,所以上面的两个参数没啥用。
-Xmn 设置 young generation 的 heap 大小
-XX:MinHeapFreeRatio 与 -XX:MaxHeapFreeRatio 设定空闲内存占总内存的比例范围,这两个参数会影响 GC 的频率和单次 GC 的耗时。-XX:NewRatio 决定 young 与 old generation 的比例。Young generation 空间越大,minor collection 频率越低,但是 old generation 空间小了,又可能导致 major collection 频率增加。-XX:NewSize 和 -XX:MaxNewSize 直接指定了 young generation 的缺省大小和最大大小。
**非堆内存** 的设置
默认分配为 64M
-XX:PermSize 设置最小分配空间,-XX:MaxPermSize 设置最大分配空间。一般把这两个数值设为相同,以减少申请内存空间的时间。
再讲解和笔记下,JDK 下的一些相关看内存管理工具的使用:
查看 jvm 内存状态:
jstat -gcutil pid 1000 20
异常情况的例子
jstat -gcutil pid 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 99.99 82.51 53.11 2409 1.205 10117 7250.393 7251.598
0.00 0.00 83.42 82.55 53.10 2409 1.205 10118 7252.650 7253.855
0.00 0.00 56.06 82.46 53.10 2410 1.205 10120 7254.467 7255.672
0.00 0.00 32.11 82.55 53.10 2411 1.205 10121 7256.673 7257.877
0.00 0.00 99.99 82.55 53.10 2412 1.205 10123 7257.026 7258.231
0.00 0.00 76.00 82.50 53.10 2412 1.205 10124 7259.241 7260.446
这个数据显示 Full GC 频繁发生。
正常情况的例子
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
参数含义:
S0:Heap 上的 Survivor space 0 段已使用空间的百分比
S1:Heap 上的 Survivor space 1 段已使用空间的百分比
E:Heap 上的 Eden space 段已使用空间的百分比
O:Heap 上的 Old space 段已使用空间的百分比
P:Perm space 已使用空间的百分比
YGC:从程序启动到采样时发生 Young GC 的次数
YGCT:Young GC 所用的时间(单位秒)
FGC:从程序启动到采样时发生 Full GC 的次数
FGCT:Full GC 所用的时间(单位秒)
GCT:用于垃圾回收的总时间(单位秒)
2 Dump 出内存
2.1 找出要 dump 的线程 pid
在 Linux 下,使用 ps –aux
2.2 Dump 出内存使用详情
可以通过命令:
jmap -dump:file=a.hprof pid
例如:jmap -heap 2343, 可以看到
Attaching to process ID 2343, please wait…
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0-b16
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 4294967296 (4096.0MB)
NewSize = 2686976 (2.5625MB)
MaxNewSize = -65536 (-0.0625MB)
OldSize = 5439488 (5.1875MB)
NewRatio = 2 (YG,OG 大小比为 1:2)
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 268435456 (256.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 1260060672 (1201.6875MB)
used = 64868288 (61.86322021484375MB)
free = 1195192384 (1139.8242797851562MB)
5.148028935546367% used
From Space:
capacity = 85524480 (81.5625MB)
used = 59457648 (56.70323181152344MB)
free = 26066832 (24.859268188476562MB)
69.52120375359195% used
To Space:
capacity = 85852160 (81.875MB)
used = 0 (0.0MB)
free = 85852160 (81.875MB)
0.0% used
~~~~~~~~~~~~~~~~~~~~~~~~~~ 这三块为上面所说的 YG 大小和使用情况
PS Old Generation
capacity = 2291138560 (2185.0MB)
used = 1747845928 (1666.8757705688477MB)
free = 543292632 (518.1242294311523MB)
76.28722062099989% used
~~~~~~~~~~~~~~~~~~~~~~~~~~OG 大小和使用情况
PS Perm Generation
capacity = 108265472 (103.25MB)
used = 107650712 (102.6637191772461MB)
free = 614760 (0.5862808227539062MB)
99.43217353728436% used
jstat
jstat 是 vm 的状态监控工具,监控的内容有类加载、运行时编译及 GC。
使用时,需加上查看进程的进程 id,和所选参数。以下详细介绍各个参数的意义。
jstat -class pid: 显示加载 class 的数量,及所占空间等信息。
jstat -compiler pid: 显示 VM 实时编译的数量等信息。
jstat -gc pid: 可以显示 gc 的信息,查看 gc 的次数,及时间。其中最后五项,分别是 young gc 的次数,young gc 的时间,full gc 的次数,full gc 的时间,gc 的总时间。
jstat -gccapacity: 可以显示,VM 内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN 显示的是最小 perm 的内存使用量,PGCMX 显示的是 perm 的内存最大使用量,PGC 是当前新生成的 perm 内存占用量,PC 是但前 perm 内存占用量。其他的可以根据这个类推,OC 是 old 内纯的占用量。
jstat -gcnew pid:new 对象的信息。
jstat -gcnewcapacity pid:new 对象的信息及其占用量。
jstat -gcold pid:old 对象的信息。
jstat -gcoldcapacity pid:old 对象的信息及其占用量。
jstat -gcpermcapacity pid: perm 对象的信息及其占用量。
jstat -util pid: 统计 gc 信息统计。
jstat -printcompilation pid: 当前 VM 执行的信息。
除了以上一个参数外,还可以同时加上 两个数字,如:jstat -printcompilation 3024 250 6 是每 250 毫秒打印一次,一共打印 6 次,还可以加上 -h3 每三行显示一下标题。
例子:
jstat -gcutil pid 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT
47.49 0.00 64.82 46.08 47.69 20822 2058.631 68 22.734 2081.365
0.00 37.91 38.57 46.13 47.69 20823 2058.691 68 22.734 2081.425 这里发生了一次 YG GC,也就是 MinorGC,耗时 0.06s
46.69 0.00 15.19 46.18 47.69 20824 2058.776 68 22.734 2081.510
46.69 0.00 74.59 46.18 47.69 20824 2058.776 68 22.734 2081.510
0.00 40.29 19.95 46.24 47.69 20825 2058.848 68 22.734 2081.582
MajorGC 平均时间:22.734/68=0.334 秒
MinorGC 平均时间:2058.691/20823=0.099 秒