开 源 力 量 公 开 课 第 1 期 : 生 产 环 境 下 的 Java 排 错 调 优 2012 年 12 月 25 日 18:30-21:30 http://www.osforce.cn
生 产 环 境 下 的 Java 排 错 调 优 @ 施 懿 民
远 程 调 试
远 程 调 试 架 构 Java 平 台 调 试 器 架 构 组 件 被 调 程 序 -----( 调 试 器 接 口 / -------------- / VM -------------- <---- JVMTI Java 虚 拟 机 工 具 接 口 \ 后 台 \ -------------- / 通 信 渠 道 --( <------------ JDWP Java 调 试 传 输 协 议 \ / -------------- / 前 台 调 试 器 -----( -------------- <---- JDI Java 调 试 接 口 \ UI \ -------------- 第 4 页
远 程 调 试 原 理 通 过 客 户 机 - 服 务 器 架 构, 可 以 在 本 地 调 试 Java 程 序, 也 可 以 通 过 网 络 进 行 远 程 调 试, JPDA 规 范 中 的 两 个 术 语 : 连 接 器 和 传 输 连 接 器 是 一 个 JDI 抽 象, 用 来 在 调 试 器 应 用 程 序 和 目 标 VM 之 间 建 立 连 接 传 输 定 义 应 用 程 序 如 何 进 行 访 问, 以 及 数 据 如 何 在 前 端 和 后 端 之 间 传 输 连 接 器 映 射 到 可 用 的 传 输 类 型 和 连 接 模 式 在 Sun 的 JPDA 参 考 实 现 中, 为 Microsoft Windows 提 供 了 两 个 传 输 机 制 : 套 接 字 传 输 和 共 享 内 存 传 输 可 用 的 连 接 器 : 连 接 套 接 字 连 接 器 连 接 共 享 内 存 连 接 器 监 听 套 接 字 连 接 器 监 听 共 享 内 存 连 接 器 启 动 命 令 行 连 接 器 第 5 页
远 程 调 试 命 令 参 数 -Xdebug: 启 用 调 试 特 性 -Xrunjdwp:<sub-options> : 在 目 标 VM 中 加 载 JDWP 实 现 它 通 过 传 输 和 JDWP 协 议 与 独 立 的 调 试 器 应 用 程 序 通 信 下 面 介 绍 一 些 特 定 的 子 选 项 从 Java V5 开 始, 您 可 以 使 用 -agentlib:jdwp 选 项, 而 不 是 -Xdebug 和 - Xrunjdwp 但 如 果 连 接 到 V5 以 前 的 VM, 只 能 选 择 -Xdebug 和 -Xrunjdwp -Xrunjdwp 子 选 项 transport: 这 里 通 常 使 用 套 接 字 传 输 但 是 在 Windows 平 台 上 也 可 以 使 用 共 享 内 存 传 输 Server: 如 果 值 为 y, 目 标 应 用 程 序 监 听 将 要 连 接 的 调 试 器 应 用 程 序 否 则, 它 将 连 接 到 特 定 地 址 上 的 调 试 器 应 用 程 序 address: 这 是 连 接 的 传 输 地 址 如 果 服 务 器 为 n, 将 尝 试 连 接 到 该 地 址 上 的 调 试 器 应 用 程 序 否 则, 将 在 这 个 端 口 监 听 连 接 suspend: 如 果 值 为 y, 目 标 VM 将 暂 停, 直 到 调 试 器 应 用 程 序 进 行 连 接 第 6 页
1 被 调 试 程 序 当 作 调 试 服 务 器 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8765 2 被 调 程 序 当 作 调 试 客 户 端 -Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8000 演 示 设 置 远 程 调 试 第 7 页
断 点 的 实 现 原 理 断 点 (Break Point) 可 以 说 是 调 试 器 的 关 键 技 术, 需 要 软 件 和 硬 件 的 协 作 才 能 实 现 一 般 断 点 的 实 现 方 式 有 下 面 几 种 : 1. 通 过 特 定 的 指 令 通 知 中 央 处 理 器 (CPU) 来 中 断 程 序 的 执 行 2. 通 过 设 置 特 定 的 寄 存 器 来 通 知 中 央 处 理 器 中 断 程 序 的 执 行 3. 通 过 强 制 处 理 器 触 发 异 常 来 中 断 程 序 执 行 并 将 控 制 权 转 交 给 调 试 器 在 Intel 兼 容 的 处 理 器 架 构 上, 一 般 调 试 器 是 通 过 在 进 程 中 特 定 的 位 置 插 入 INT 3 指 令 来 实 现 断 点 的 调 试 器 提 供 的 单 步 执 行, 单 步 跳 过 执 行 以 及 跳 出 函 数 等 功 能, 都 是 断 点 的 变 种 第 8 页
1 在 C 程 序 中 嵌 入 断 点 演 示 第 9 页
特 殊 断 点 除 了 简 单 的 每 次 执 行 到 断 点 位 置 中 断 程 序 执 行 这 一 种 方 式, 调 试 器 一 般 都 提 供 了 如 下 几 种 断 点 : 1. 条 件 断 点 可 以 指 定 触 发 断 点 的 条 件, 避 免 每 次 重 复 触 发 断 点 降 低 调 试 工 作 效 率 2. 监 视 断 点 可 以 在 访 问 数 据 的 时 候, 中 断 程 序 的 执 行 3. 函 数 断 点 可 以 在 执 行 函 数 前 或 者 退 出 函 数 前 中 断 程 序 的 执 行 4. 异 常 断 点 当 程 序 发 生 指 定 异 常 的 时 候, 中 断 程 序 的 执 行, 第 一 时 间 发 现 问 题 所 在 5. 类 型 断 点 当 程 序 试 图 加 载 某 个 类 型 的 时 候, 中 断 程 序 的 执 行 第 10 页
1 禁 用 所 有 的 断 点 2 设 置 条 件 断 点 3 监 视 断 点 4 异 常 断 点 5 函 数 断 点 6 在 类 型 加 载 的 时 候 中 断 演 示 第 11 页
1 在 堆 栈 的 任 意 位 置 重 新 执 行 语 句 2 在 程 序 启 动 时 进 行 调 试 3 使 用 变 量 窗 口 的 逻 辑 视 图 4 单 步 过 滤 调 试 5 计 算 表 达 式 演 示 Eclipse 其 他 调 试 技 巧 第 12 页
1 使 用 jdb 调 试 java 程 序 演 示 第 13 页
在 Emacs 里 运 行 JDB 由 于 直 接 使 用 JDB 调 试 时, 浏 览 源 代 码 时 很 不 方 便, 如 果 机 器 上 安 装 了 emacs, 可 以 直 接 在 emacs 里 启 动 JDB, 获 取 跟 eclipse 相 近 的 源 代 码 级 别 的 调 试 体 验 在 emacs 里 运 行 JDB 的 方 法 : 在 emacs 里 按 下 ALT+X 键, 在 提 示 符 后 面 输 入 JDB, 敲 击 回 车 接 着 再 输 入 JDB 的 启 动 参 数 按 下 CTRL + X,2 键, 将 emacs 分 屏 再 按 CTRL + X, B 键, 将 其 中 一 个 屏 幕 显 示 源 代 码 按 CTRL + X, O 键, 再 两 个 屏 幕 间 切 换 在 JDB 的 那 个 窗 口 里 输 入 正 常 的 调 试 命 令 第 14 页
JAVA 内 存 调 优
概 述 Java 虽 然 有 垃 圾 回 收 机 制, 但 是 程 序 编 写 不 慎, 还 是 会 发 生 内 存 泄 露 导 致 OutOfMemoryError 的 发 生 本 节 课 讲 解 了 GC 的 机 制, 以 及 JDK 自 带 的 HPROF 工 具 以 分 析 内 存 问 题 第 16 页
Java GC 简 介 所 有 Java 对 象 都 是 分 配 在 Java 堆 上 面 的 ; Java 上 使 用 垃 圾 回 收 机 制 回 收 没 有 引 用 到 的 对 象 ; Java 虚 拟 机 有 专 门 的 GC 线 程 用 来 执 行 垃 圾 回 收 ; 当 GC 线 程 从 内 存 删 除 一 个 对 象 时, 首 先 会 调 用 对 象 的 finalize 函 数, 在 这 个 函 数 里 可 以 执 行 自 定 义 的 释 放 资 源 操 作 ; Java 程 序 自 身 无 法 强 制 启 动 GC, 即 使 使 用 System.gc() 和 Runtime.gc() 这 样 的 函 数, 也 只 是 递 交 一 个 GC 请 求 给 GC 线 程 ; 当 无 法 在 Java 内 存 堆 (Java heap) 上 创 建 对 象 时,Java 虚 拟 机 会 抛 出 OutOfMemoryError 对 象 没 有 被 其 他 对 象 引 用, 是 指 从 GC Root 开 始 遍 历, 无 法 遍 历 到 的 对 象,GC Root 包 括 : Class 系 统 里 加 载 的 类, 这 些 类 不 会 被 卸 载, 类 里 的 静 态 变 量 可 能 会 引 用 其 它 Java 对 象 Thread 正 在 运 行 的 线 程 堆 栈 上 的 局 部 变 量 堆 栈 上 的 函 数 还 要 运 行, 因 此 他 们 引 用 到 的 对 象 都 是 有 用 的 JNI 参 数 和 局 部 变 量 锁 (Monitor) - 用 于 线 程 同 步 第 17 页
Java GC 堆 结 构 Java 堆 分 成 3 个 部 分, 或 称 作 届 (generation), 分 别 是 Young(New) generation, Tenured(Old) generation,perm Area of heap 而 New generation 又 细 分 成 Eden space, Survivor 1 和 Survivor 2 新 的 对 象 总 是 先 在 Eden space 上 创 建, 经 过 minor GC 后, 剩 余 的 会 挪 到 Survivor 1, 接 着 就 是 Survivor 2 当 执 行 过 Major GC 后, 对 象 会 被 挪 到 Old generation 中 Perm area 主 要 是 用 来 保 存 Java 类 型 以 及 函 数 的 元 数 据 信 息, 有 的 内 在 化 (internalization) 的 字 符 串 也 会 放 在 里 面 第 18 页
Java GC 器 虚 拟 机 提 供 了 好 几 个 GC 收 集 器,Java 5 在 Serial GC 之 外, 还 添 加 了 几 个 GC 收 集 器 : Serial GC: 只 使 用 一 个 GC 线 程 执 行 垃 圾 回 收 工 作, 在 执 行 GC 时, 其 他 线 程 都 会 暂 停 工 作, 收 集 young generation 里 的 垃 圾 对 象 Parallel (Throughput) GC: 使 用 多 个 GC 线 程 并 行 执 行 垃 圾 回 收 工 作, 在 执 行 GC 时, 其 他 线 程 都 会 暂 停 工 作, 收 集 young generation 里 的 垃 圾 对 象 Concurrent Mark Sweep(CMS) GC: 用 于 收 集 old generation 里 的 垃 圾 对 象, 跟 其 他 线 程 并 行 工 作, 当 需 要 标 注 某 个 线 程 里 的 垃 圾 对 象 时, 会 暂 停 线 程 一 小 会, 其 他 时 候 可 以 与 线 程 并 行 执 行 在 GC 时, 通 常 young generation 里 的 GC, 即 minor GC 很 快, 当 old generation 空 间 不 够 时,Java 虚 拟 机 首 先 会 尝 试 CMS GC 并 行 收 集, 如 果 这 样 空 间 还 不 能 快 速 回 收 时, 那 Java 虚 拟 机 会 暂 停 所 有 线 程 执 行 GC, 这 个 时 候 称 为 Full GC 一 般 来 说,Full GC 的 执 行 效 率 要 比 minor GC 慢 很 多, 程 序 优 化 的 目 标 也 是 尽 量 减 少 Full GC 的 执 行 次 数 第 19 页
Java 内 存 堆 Java 虚 拟 机 在 启 动 时, 会 从 操 作 系 统 申 请 一 大 块 内 存, 后 续 Java 程 序 运 行 时, 所 有 对 象 都 在 这 个 内 存 块 里 分 配, 这 个 内 存 块 叫 Java Heap Java 内 存 堆 在 Java 程 序 启 动 后 无 法 更 改, 只 能 通 过 修 改 Java 程 序 的 -Xms Xmx -Xmn 等 启 动 参 数 改 变 设 置 当 Java 堆 内 存 用 光, 而 且 GC 也 无 法 收 集 更 多 的 内 存 时, 抛 出 OutOfMemoryError 可 以 使 用 Jconsole Runtime.maxMemory() Runtime.totalMemory() 以 及 Runtime.freeMemory() 等 函 数 查 询 Java 程 序 的 内 存 堆 设 置 第 20 页
JDK 内 存 工 具 使 用 介 绍 - JMap Jmap 可 以 用 来 打 印 一 个 运 行 中 的 Java 程 序 或 者 Java 内 存 文 件 的 内 存 使 用 率 统 计 Jmap 还 可 以 与 jsadebugd 后 台 出 现 同 时 使 用, 查 询 统 计 远 程 机 器 上 的 Java 程 序 的 内 存 使 用 率 情 况 使 用 -heap 选 项 来 收 集 下 列 Java 内 存 使 用 率 情 况 : 1 垃 圾 回 收 算 法 相 关 的 信 息 2 内 存 堆 (Heap) 的 设 置 3 内 存 使 用 率 情 况 在 ubuntu 上 需 要 执 行 命 令 : echo 0 sudo tee /proc/sys/kernel/yama/ptrace_scope 使 用 -histo 选 项 获 取 按 类 型 统 计 的 内 存 使 用 率 情 况 使 用 -permstat 选 项 来 统 计 永 久 性 内 存 的 使 用 率 情 况, 永 久 性 内 存 是 Java 虚 拟 机 用 来 保 存 类 型 函 数 等 对 象 和 内 在 化 (internalization) 字 符 串 的 区 域 一 般 在 调 试 JSP 等 经 常 生 成 和 加 载 大 量 类 型 的 Java 程 序 很 有 用 第 21 页
1 jmap heap 的 输 出 解 释 2 jmap histo 的 输 出 解 释 3 jmap permstat 的 输 出 解 释 示 例 第 22 页
JDK 内 存 工 具 使 用 介 绍 - JHat jhat 可 以 分 析 一 个 二 进 制 的 hprof 日 志 文 件, 提 供 一 个 web 界 面 用 来 查 询 和 分 析 java 的 内 存 使 用 情 况, 其 提 供 了 一 种 类 似 SQL 的 OQL 查 询 语 句 使 得 这 个 查 询 变 得 很 简 单 可 以 用 它 来 找 出 一 些 垃 圾 对 象 的 意 外 引 用 从 而 导 致 垃 圾 无 法 回 收, 也 就 引 发 了 内 存 泄 露 OQL 的 语 法 是 : Select 选 择 用 的 Javascript 表 达 式 from [instanceof] 类 名 对 象 名 where Javascript 语 法 的 布 尔 表 达 式
1 使 用 jmap 和 jhat 等 工 具 分 析 Java 程 序 内 存 泄 露 问 题 示 例 第 24 页
THANK YOU