内存溢出(OutOfMemoryError, OOM)是Ubuntu环境下WebLogic Server的常见问题,主要表现为应用崩溃、响应延迟或日志中出现java.lang.OutOfMemoryError报错。解决该问题需从排查定位、JVM调优、代码修复、系统优化多维度入手,以下是具体步骤:
确认内存溢出症状
检查WebLogic日志(位于域目录的logs文件夹,如/u01/domains/your_domain/logs/AdminServer.log),若存在java.lang.OutOfMemoryError(如OutOfMemoryError: Java heap space、OutOfMemoryError: PermGen space或GC overhead limit exceeded),则可初步判定为内存溢出。
实时监控JVM内存使用
使用jstat命令查看堆内存分配与垃圾回收情况,例如:
jstat -gcutil <WebLogic进程ID> 1000 # 每秒刷新一次,观察Eden区、老年代、永久代的使用率及GC次数
若老年代(O列)使用率持续接近100%或Full GC(FGC列)频率过高(如每分钟超过1次),说明堆内存不足或存在内存泄漏。
获取堆转储文件
在WebLogic启动脚本(bin/setDomainEnv.sh)中添加以下JVM参数,或在运行时通过jmap命令生成堆转储文件(用于分析内存中对象分布):
# 启动参数方式(推荐)
export JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof"
# 手动命令方式(需知道进程ID)
jmap -dump:format=b,file=/tmp/heapdump.hprof <WebLogic进程ID>
堆转储文件会记录内存中所有对象的类型、数量及引用链,是定位内存泄漏的关键证据。
分析内存泄漏点
使用Eclipse Memory Analyzer(MAT)或VisualVM打开堆转储文件,重点关注:
java.util.LinkedHashMap、自定义集合类);LinkedHashMap积累了数百万个Entry且占用4GB以上内存,可能是缓存未设置大小限制导致的泄漏。调整堆内存大小
根据应用实际需求修改setDomainEnv.sh中的-Xms(初始堆大小)和-Xmx(最大堆大小),建议两者设置为相同值(避免堆内存动态扩展带来的性能损耗)。例如:
export JAVA_OPTS="$JAVA_OPTS -Xms2048m -Xmx2048m" # 初始和最大堆均为2GB
注意:堆大小不宜超过Ubuntu系统可用内存的70%(需预留内存给系统和其他进程)。
优化永久代/元空间
-XX:MaxPermSize):export JAVA_OPTS="$JAVA_OPTS -XX:MaxPermSize=512m" # 永久代最大大小设为512MB
-XX:MaxMetaspaceSize):export JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=512m" # 元空间最大大小设为512MB
永久代/元空间溢出常表现为OutOfMemoryError: PermGen space,主要原因是类加载过多(如动态生成类、重复加载类)。
开启GC日志
添加以下参数记录垃圾回收详情,便于分析GC频率、耗时及内存回收效率:
export JAVA_OPTS="$JAVA_OPTS -Xloggc:/tmp/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps"
通过gc.log可判断是否因GC频繁(如Young GC每秒1次)或Full GC耗时过长(如超过2秒)导致的内存溢出。
选择合适的垃圾回收器
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200" # 目标最大GC停顿时间200ms
export JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection"
选择合适的GC器可减少GC停顿时间,提升应用响应速度。
修复代码中的内存泄漏
static Map)的生命周期与应用一致,若持续向其中添加对象(如缓存未设置过期时间),会导致内存无限增长。应使用WeakHashMap(弱引用)或设置缓存大小限制(如Guava Cache的maximumSize)。ResultSet等资源在使用后通过try-with-resources或finally块关闭,避免资源泄漏。例如:try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
// 处理结果集
} catch (SQLException e) {
// 异常处理
}
BufferedReader逐行读取)、批量处理数据时分批次提交(如Hibernate的batch-size设置为50~100)。优化WebLogic配置
ExecuteThreadTotalCPUUsage超过80%),会导致线程竞争加剧、内存消耗增加。可通过WebLogic控制台(Domain Structure > Environment > Servers > AdminServer > Configuration > Tuning)调整ExecuteThreadTotal(默认值为15),建议设置为CPU核心数的1~2倍。weblogic.jdbc.common.internal.ConnectionPool)过大(如MaxCapacity超过100)会导致连接未及时释放,占用内存。应设置合理的MaxCapacity(如50)和InitialCapacity(如10),并启用TestOnBorrow(借出连接时检查有效性)。setDomainEnv.sh中禁用相关模块,减少内存占用。增加物理内存
若应用内存需求超过Ubuntu系统的物理内存(可通过free -h查看),需升级服务器内存(如从8GB增至16GB),避免因内存不足导致频繁使用Swap分区(Swap会显著降低性能)。
调整Swap分区
若物理内存不足,可适当扩大Swap分区(默认大小通常为物理内存的1~2倍)。例如,创建2GB的Swap文件:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
永久生效需将/swapfile none swap sw 0 0添加到/etc/fstab文件中。
优化内核参数
修改/etc/sysctl.conf文件,调整以下参数以提升内存管理效率:
vm.swappiness=10 # 降低Swap使用倾向(值越小越倾向于使用物理内存,范围0~100)
vm.dirty_ratio=10 # 当脏页(未写入磁盘的内存页)占总内存的10%时触发刷盘
vm.dirty_background_ratio=5 # 当脏页占5%时后台开始刷盘
生效命令:sudo sysctl -p。
使用cgroups限制资源
通过cgroups限制WebLogic进程的内存使用(避免单个进程占用所有内存导致系统崩溃)。例如,创建一个cgroup:
sudo cgcreate -g memory:/weblogic_group
echo 2G | sudo tee /sys/fs/cgroup/memory/weblogic_group/memory.limit_in_bytes # 限制内存为2GB
echo <WebLogic进程ID> | sudo tee /sys/fs/cgroup/memory/weblogic_group/tasks # 将进程加入cgroup
通过以上步骤,可系统性解决Ubuntu上WebLogic的内存溢出问题。需注意的是,内存泄漏是根本原因,需通过代码分析与修复彻底消除;JVM调优与系统优化则是辅助手段,可提升应用的稳定性与性能。