jvm
内存结构
oom: OutOfMemoryError
soe: StackOverflowError
TODO 整理各个区域的异同
TODO 整理OOM后面各种错误信息
- unable to create new native thread
是否会oom,是否会soe
是否线程私有/线程共享
是否会垃圾回收
| 区域 | 是否会OutOfMemory | 是否会StackOverflowError | 是否会gc |
|---|---|---|---|
| 程序计数器 | N | N | N |
| 本地方法栈 | Y | Y | N |
| 虚拟机栈 | Y | Y | N |
| java堆 | Y | Y | Y |
| 方法区 | Y | Y | Y |
程序计数器(Program Counter Register)
用于记录下一条要运行的指令的地址。是线程私有的内存空间。
(若当前线程正在执行一个java方法,程序计数器记录的是正在执行的java字节码地址,若当前线程正在执行一个native方法,则为undefined)
此内存区域不会发生OutOfMemoryError。
虚拟机栈
是线程私有的内存空间。
此内存区域会发生StackOverflowError和OutOfMemoryError。
-Xss
栈帧:方法在被调用时的一种数据结构,存放了方法的局部变量表、操作数栈、动态连接方法、返回地址、其它信息。
局部变量表中,long/double占用64位,其它类型(byte,short,char,int,float,对象引用)占32位。
局部变量表是GC Roots之一。
本地方法栈
本地方法是用C/C++实现的。
此内存区域会发生StackOverflowError和OutOfMemoryError。
java堆
堆空间分为新生代和老年代。
新生代又分为Eden/survior0/survior1。
被所有线程共享
/**
* java8中
* -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -Xms40M -Xmx40M -Xmn20M
*/
public class ObjectWasCreateAtEden {
final static int _1M = 1024 * 1024;
public static void main(String[] args) {
byte[] b1 = new byte[_1M / 10];
byte[] b2 = new byte[_1M * 10];
b2 = null;
b2 = new byte[_1M * 8];
System.gc(); // 调用此命令后,新生代被清空
}
}
[GC (System.gc()) [PSYoungGen: 14280K->1345K(18432K)] 22472K->9545K(38912K), 0.0033214 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 1345K->0K(18432K)] [ParOldGen: 8200K->9450K(20480K)] 9545K->9450K(38912K), [Metaspace: 3322K->3322K(1056768K)], 0.0128114 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
Heap
PSYoungGen total 18432K, used 164K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
eden space 16384K, 1% used [0x00000000fec00000,0x00000000fec290d0,0x00000000ffc00000)
from space 2048K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x00000000ffe00000)
to space 2048K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x0000000100000000)
ParOldGen total 20480K, used 9450K [0x00000000fd800000, 0x00000000fec00000, 0x00000000fec00000)
object space 20480K, 46% used [0x00000000fd800000,0x00000000fe13aa48,0x00000000fec00000)
Metaspace used 3332K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 363K, capacity 388K, committed 512K, reserved 1048576K
方法区
HotSpot中称方法区为永久区。
所有线程共享该区域。
方法区主要保存的是类的元数据、常量池、方法信息。
对方法区GC的回收,从如下两个方面:
- 对常量池的回收 (String#intern())
- 对类元数据的回收 (两个条件:一个类的所有实例已被回收,加载该类的ClassLoader也已被回收)
类加载
GC (garbage collection)
GC在jvm中的应用
命令
- jps -lvVm
- jstack $pid [ > c:/tmp/web-tester-stack.log ]
- jmap -histo $pid [ > c:/tmp/map.log]
- 如何知道eden s0 s1 old的大小?
jmap -heap $pid [ > c:/tmp/map.log]
# jmap -heap 2696或者jhsdb jmap --heap --pid 2696
Attaching to process ID 2696, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 21.0.6+8-LTS-jvmci-23.1-b55
using thread-local object allocation.
Garbage-First (G1) GC with 13 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 209715200 (200.0MB)
NewSize = 1363144 (1.2999954223632812MB)
MaxNewSize = 125829120 (120.0MB)
OldSize = 5452592 (5.1999969482421875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 22020096 (21.0MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 1048576 (1.0MB)
Heap Usage:
G1 Heap:
regions = 200
capacity = 209715200 (200.0MB)
used = 75363072 (71.871826171875MB)
free = 134352128 (128.128173828125MB)
35.9359130859375% used
G1 Young Generation:
Eden Space:
regions = 2
capacity = 131072000 (125.0MB)
used = 2097152 (2.0MB)
free = 128974848 (123.0MB)
1.6% used
Survivor Space:
regions = 0
capacity = 1048576 (1.0MB)
used = 14448 (0.0137786865234375MB)
free = 1034128 (0.9862213134765625MB)
1.37786865234375% used
G1 Old Generation:
regions = 76
capacity = 77594624 (74.0MB)
used = 73251472 (69.85804748535156MB)
free = 4343152 (4.1419525146484375MB)
94.4027668720967% used
- jmap -dump:file=c:/tmp/web-tester.bin $pid
- 查看gc相关
jstat -gcutil $pid
jstat -gcutil 2696 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT
- 1.57 2.56 99.75 98.35 93.88 187 0.342 1 0.029 4 0.006 0.376
- 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378
- 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378
- 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378
- 1.97 1.60 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378
- 1.97 1.60 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378
//S0 — 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
//S1 — 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
//E — 年轻代中Eden(伊甸园)已使用的占当前容量百分比
//O — Heap上的 Old space 区已使用空间的百分比
//P — Perm space 区已使用空间的百分比
YGC: 年轻代垃圾回收次数
YGCT: 年轻代垃圾回收消耗的时间 (秒)
FGC: 老年代垃圾回收次数
FGCT: 老年代垃圾回收消耗的时间 (秒)
CGC: 压缩类空间垃圾回收次数
CGCT: 压缩类空间垃圾回收消耗的时间 (秒)
GCT: 总的垃圾回收消耗的时间 (秒)
- jstat -gc PID 1000 10 (每秒查看一次gc信息,共10次)
- 查看运行中的jvm的启动参数
Java VisualVM
- 如何查看一个运行中的java进程的Xss参数。 jinfo -flag ThreadStackSize pid (可尝试启动一个java进程添加-Xss2m来测试,我jdk-1.8.0_121启动一个简单的没有配置任何Xss的main方法,该值是0)-Xss is translated in a VM flag named ThreadStackSize
- XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseConcMarkSweepGC
- XX:CMSInitiatingOccupancyFraction=75,网上有提到JVM提供了3种垃圾收集器,如果是长生命周期(老年代)对象较多时可以使用CMS收集器。
jvm内存分配参数
win7 x64 jdk-8u121上使用如下参数
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -Xmx32M -Xms32M -Xloggc:c:/tmp/gclog/forgc1.log -XX:+PrintVMOptions -XX:+PrintFlagsFinal -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/tmp/gclog/haep.dump
loggc中显示CommandLine flags: -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -Xmx32M -Xms32M -Xloggc:c:/tmp/gclog/forgc1.log -XX:+PrintVMOptions -XX:+PrintFlagsFinal -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/tmp/gclog/haep.dump
- -Xms --> -XX:InitialHeapSize 最小堆
- -Xmx --> -XX:MaxHeapSize 最大堆
- -XX:MinHeapFreeRatio 堆空间的最小空闲比例,当堆空间的空闲内存小于这个数值时,jvm便会扩展堆空间
- -XX:MaxHeapFreeRatio 堆空间的最大空闲比例,当堆空间的空闲内存大于这个数值时,jvm便会压缩堆空间
- -Xss 设置线程栈大小
- -Xmn 设置新生代的大小,该参数的效果等同于设置了-XX:NewSize和-XX:MaxNewSize,如-Xmn100M (-XX:MaxNewSize=10485760 -XX:NewSize=10485760)
- -XX:NewSize=11010048 -XX:MaxNewSize=11010048 为-Xmx的1/3
- -XX:+PrintFlagsFinal
- Eden与s0s1的空间会动态变化
- -XX:PermSize和-XX:MaxPermSize用来设置永久代的初始和最大值
- 堆的比例分配-XX:SurvivorRatio用来设置新生代中eden与s0空间的比例,-XX:SurvivorRatio=eden/s0=eden/s1
- -XX:NewRatio 老年代/新生代的比率,默认是2,所以就有了下面的NewSize为1/3
- -XX:TargetSurviorRatio 设置survior区的可使用率,当使用率达到该数值时,会将对象送入老年代。
-XX:PretenureSizeThreshold 当新创建的对象大小超过此值时会直接在老年代分配
-XX:+DisableExplicitGC 禁用显式GC(即System.gc())
gc调优,即是尽可能将对象预留在新生代,减少老年代gc的次数
引用
| 引用类型 | 是否会被回收 | --- |
|---|---|---|
| 强引用 | 不会 | --- |
| 软引用 | 内存不够时会 | --- |
| 弱引用 | 会 | --- |
| 虚引用 | 会 | --- |
关闭windows的虚拟内存会导致内存不够用,进而会导致idea出现jvm错误:
[thread 8996 also had an error]
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 32744 bytes for ChunkPool::allocate
# An error report file with more information is saved as:
# D:\shigoto\code\datatist-wolf\hs_err_pid8316.log
[thread 8768 also had an error]
[thread 4352 also had an error]
[error occurred during error reporting , id 0xe0000001]
最后编辑:张三 更新时间:2025-03-07 21:22