不求甚解

此博客为个人学习之用,如与其他作品雷同,纯属巧合。

导航

1. 前置准备

确保服务器上已安装以下工具(通常 Linux 发行版默认都有,但 lrzsz 可能需要手动安装):

  • JDK: 必须包含 jmap 命令(通常在 $JAVA_HOME/bin 下)。
  • lrzsz: 用于 sz 命令。
    • CentOS/RedHat: yum install -y lrzsz
    • Ubuntu/Debian: apt-get install -y lrzsz

2. 创建脚本文件

vi dump_heap.sh

3. 赋予执行权限

chmod +x dump_heap.sh

4. (可选) 修改配置

修改顶部的配置区:

KEYWORD="你的进程关键词"      # 比如 "my-app.jar" 或 "com.example.Main"
DUMP_DIR="./dump"            # 输出目录
SPLIT_SIZE="1G"              # 分卷大小,如果网络好可以改大,网络差改小 (如 500M)

5. 执行脚本

./dump_heap.sh

6. 脚本内容

#!/bin/bash
set -e

# ================= 配置区 =================
KEYWORD="yh-hsb-engine.jar"    # 进程关键词,用于匹配目标 Java 进程
DUMP_DIR="./dump"              # 堆 dump 文件及压缩包的输出目录
RAW_FILE_NAME="heapdump.hprof" # jmap 生成的原始堆 dump 文件名
BASE_NAME="heapdump"           # 最终压缩包的基础文件名(不含后缀)
SPLIT_SIZE="1000m"                # 分卷大小 (1G = 1024MB),超过阈值时每个分卷的大小
SIZE_LIMIT=1073741824          # 分割阈值(字节),约 1024MB,超过此值才触发分卷
# =========================================

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DUMP_PATH="${SCRIPT_DIR}/${DUMP_DIR/#.\//}" 
mkdir -p "$DUMP_PATH"

RAW_FILE="${DUMP_PATH}/${RAW_FILE_NAME}"
TAR_FILE="${DUMP_PATH}/${BASE_NAME}.tar.gz"

# 1. 获取 PID
PID=$(ps -ef | grep "$KEYWORD" | grep -v grep | head -n 1 | awk '{print $2}')
[ -z "$PID" ] && echo "Error: Process '$KEYWORD' not found!" && exit 1
echo "Found PID: $PID"

# 2. 执行 Dump
echo "Dumping heap..."
jmap -dump:live,format=b,file="$RAW_FILE" "$PID" || exit 1

# 3. 压缩前清理旧文件
# 只清理旧的 .tar.gz 及其分卷,确保本次生成的文件名不冲突
echo "Cleaning up old archive files before compressing..."
rm -f "${DUMP_PATH}/${BASE_NAME}.tar.gz"* 2>/dev/null || true

# 4. 压缩 (Tar + Gzip)
echo "Compressing..."
tar -czf "$TAR_FILE" -C "$DUMP_PATH" "$RAW_FILE_NAME"
# 压缩成功后删除原始 hprof 以节省空间
rm -f "$RAW_FILE" 

# 5. 判断并分割
FILE_SIZE=$(stat -c%s "$TAR_FILE")
if [ $FILE_SIZE -gt $SIZE_LIMIT ]; then
  echo "Size ($FILE_SIZE) > Limit ($SIZE_LIMIT). Splitting..."
  echo "Executing: split -b ${SPLIT_SIZE} -d -a 2 ${TAR_FILE} ${TAR_FILE}"
  
  split -b "$SPLIT_SIZE" -d -a 2 "$TAR_FILE" "$TAR_FILE"
  
  rm -f "$TAR_FILE" # 分割后删除原大文件,只保留分卷 (.00, .01...)
else
  echo "No split needed (Size: $FILE_SIZE)."
  # 不分割,保留原压缩包
fi

# 6. 展示文件
echo ""
echo "=========================================="
echo "Generated files:"
cd "$DUMP_PATH"
ls -lh ${BASE_NAME}.tar.gz*
echo "=========================================="

# 7. 询问是否发送
read -p "Send via sz? (y/n): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
  command -v sz &>/dev/null || { echo "Error: sz command not found."; exit 1; }
  
  echo "Starting transfer... (Do not interrupt)"
  sz ${BASE_NAME}.tar.gz*
  
  echo ""
  echo "Transfer finished."
  echo "Files are RETAINED in: $DUMP_PATH"
  echo "Please manually clean them up later if needed."
else
  echo "Skipped sending."
  echo "Files are RETAINED in: $DUMP_PATH"
  echo "You can send them manually later."
fi