我们有一些应用程序有时会陷入糟糕的状态,但仅限于生产(当然!).虽然进行堆转储可以帮助收集状态信息,但使用远程调试器通常更容易.设置它很容易 - 只需将其添加到他的命令行:
-Xdebug -Xrunjdwp:transport = dt_socket,server = y,suspend = n,address = PORT
似乎没有可用的安全机制,因此在生产中启用调试将有效地允许任意代码执行(通过hotswap).
我们在Solaris 9和Linux(Redhat Enterprise 4)上运行了1.4.2和1.5个Sun JVM.我们如何启用安全调试?有没有其他方法来实现我们的生产服务器检查目标?
更新:对于JDK 1.5+ JVM,可以指定调试器应绑定的接口和端口.因此,如果在服务器上正确设置了SSH,KarlP建议绑定到环回并仅使用SSH隧道连接到本地开发人员框.
但是,似乎JDK1.4x不允许为调试端口指定接口.那么,我们可以阻止访问网络中某个地方的调试端口,或者在操作系统本身中进行一些特定于系统的阻塞(如Jared建议的那样,IPChains等)?
更新#2:这是一个让我们限制风险的黑客,即使在1.4.2 JVM上也是如此:
命令行参数:
-Xdebug
-Xrunjdwp:
transport=dt_socket,
server=y,
suspend=n,
address=9001,
onthrow=com.whatever.TurnOnDebuggerException,
launch=nothing
Run Code Online (Sandbox Code Playgroud)
用于打开调试器的Java代码:
try {
throw new TurnOnDebuggerException();
} catch (TurnOnDebugger td) {
//Nothing
}
Run Code Online (Sandbox Code Playgroud)
TurnOnDebuggerException可以是任何保证不被抛出的异常.
我在Windows机器上对此进行了测试,以证明(1)调试器端口最初没有接收到连接,并且(2)抛出如上所示的TurnOnDebugger异常导致调试器变为活跃状态.启动参数是必需的(至少在JDK1.4.2上),但是JVM正好处理了垃圾值.
我们计划制作一个小型servlet,在适当的安全性之后,可以允许我们打开调试器.当然,之后无法将其关闭,调试器一旦打开就仍然会混杂地监听.但是,这些是我们愿意接受的限制,因为生产系统的调试将始终导致重新启动.
更新#3:我最后写了三个类:(1)TurnOnDebuggerException,一个简单的'ol Java异常,(2)DebuggerPoller,一个后台线程检查文件系统上是否存在指定文件,以及(3)DebuggerMainWrapper,一个类启动轮询线程,然后反射调用另一个指定类的main方法.
这是它的用法:
现在,当您启动JVM时,除了启动后台轮询器线程之外,所有内容都是相同的.假设文件(我们的名为TurnOnDebugger)最初不存在,轮询器每隔N秒检查一次.当轮询器首次注意到它时,它会抛出并立即捕获TurnOnDebuggerException.然后,代理人开始了.
您无法将其关闭,并且机器在打开时不是非常安全.从好的方面来说,我不认为调试器允许多个同时连接,因此保持调试连接是最好的防御.我们选择了文件通知方法,因为它允许我们通过在只有正确使用权限的目录中指定触发器文件来捎带我们现有的Unix authen/author.您可以轻松地构建一个通过套接字连接实现相同目的的war文件.当然,由于我们无法关闭调试器,因此我们只会在杀死病毒应用程序之前使用它来收集数据.如果有人想要这个代码,请告诉我.但是,您只需要几分钟就可以将它们放在一起.
我正在调试Sun的JDK 1.4.2_18上运行的应用程序中的内存泄漏.看来这个版本支持命令行param -XX:+ HeapDumpOnCtrlBreak,它可能导致JVM在遇到控制中断时转储堆.如何将其发送到Linux机器上的后台进程?似乎杀死信号是应该工作的方式,但是我杀了-l没有报告任何显然是Ctrl-Break的东西,至少在我的Ubuntu盒子上.
更新:我测试了使用Sun JDK 1.4.2_18杀死-3(_14是第一个以这种方式转储堆),并且它有效.已创建堆转储文件,并且该进程仍在运行.
我试图使用Eclipse MAT(内存分析工具包)来分析一些相当大的堆转储(~2G).不幸的是我的笔记本电脑有32位Windows,并且MAT耗尽了1.4G分配堆的堆空间.我成功地从大型无头64位盒子上的命令行运行堆索引器.但是,我无法说服MAT从我的笔记本电脑上的目录导入这些索引文件,以便我可以交互地调查堆.我加载堆的所有尝试(与索引文件一起)导致MAT决定重新解析堆文件而不是使用现有索引.想法?