前言
最近有个项目线上出现了内存溢出的情况,以前没出现过这种情况,排查后发现原来是启动脚本的问题,堆内存分配的不足。如果在运行Java应用程序时,设置的内存参数不足以满足应用程序的内存需求,可能会导致 OutOfMemoryError(OOM)异常,它表示Java虚拟机没有足够的内存来分配新对象。可能会有不同的子类型的OutOfMemoryError,如:
Java heap space:堆空间不足。
GC overhead limit exceeded:垃圾回收占用过多时间。
PermGen space(仅适用于Java 8及之前的版本):永久代空间不足。
StackOverflowError:当线程调用的方法调用层级太深时,将抛出此错误。
InternalError :这可能是由于JVM内部问题导致的,通常不太常见。
调整方法
1. 设置堆大小
- `-Xms<size>`:设置JVM的初始堆大小。
- `-Xmx<size>`:设置JVM的最大堆大小。
设置初始堆大小为512MB,最大堆大小为2GB:
java -Xms512m -Xmx2g -jar yourfile.jar
2. 设置栈大小
- `-Xss<size>`:设置线程的栈大小。
设置线程栈大小为256KB:
java -Xss256k -jar yourfile.jar
3. 设置永久代大小(仅适用于Java 8及之前的版本)
- `-XX:PermSize=<size>`:设置永久代初始大小。
- `-XX:MaxPermSize=<size>`:设置永久代最大大小。
设置永久代初始大小为128MB,最大大小为256MB:
java -XX:PermSize=128m -XX:MaxPermSize=256m -jar yourfile.jar
4. GC算法
Serial GC(串行GC):适用于单核处理器或小型应用程序。
-XX:+UseSerialGC
Parallel GC(并行GC):多线程垃圾回收器,适用于多核处理器和需要高吞吐量的应用程序。
-XX:+UseParallelGC
CMS GC(Concurrent Mark-Sweep GC):并发垃圾回收器,适用于需要低停顿时间的应用程序。
-XX:+UseConcMarkSweepGC
G1 GC:Garbage-First GC,适用于大内存、需要低停顿时间的应用程序。
-XX:+UseG1GC
5.GC日志
启用GC日志
-verbose:gc -Xloggc:<log_file_path>
设置GC日志文件路径
-Xloggc:/path/to/gc.log
设置GC日志文件的滚动策略
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<number_of_files> -XX:GCLogFileSize=<size>
设置GC详细信息级别
-XX:+PrintGCDetails
设置GC日志打印时间戳
-XX:+PrintGCDateStamps
设置GC日志打印时间戳的格式
-XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps
最终命令
将所有参数组合起来,得到一个完整的命令:
java -Xms512m -Xmx2g -Xss256k -XX:PermSize=128m -XX:MaxPermSize=256m +UseG1GC -verbose:gc -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -jar yourfile.jar
这个命令设置了初始堆大小为512MB,最大堆大小为2GB,线程栈大小为256KB,永久代初始大小为128MB,最大大小为256MB,将G1 GC算法与启用的GC日志一起使用,并设置了GC日志文件路径和详细信息级别。最终运行你的jar包