gdb调试转储文件_从转储调试

gdb调试转储文件

一种常见的解决问题的方法是在代码中添加调试语句以写出对象中的字段,甚至写出整个数据集。 当您发现需要越来越多的信息来理解和解决问题时,通常必须迭代执行此操作。 尽管此过程可能有效,但有时可能无法取得成果:调试代码量可能导致问题消失,您可能需要将调试添加到您不拥有的代码中,调试可能需要您重新启动过程,或者调试对整体性能的影响可能会阻止应用程序运行。

内存分析器是一个跨平台的开放源代码工具,您不仅可以使用它来诊断内存问题,还可以深入了解整个Java应用程序的状态和行为。 通过在应用程序运行时读取Java运行时创建的快照转储,Memory Analyzer提供了一种诊断调试代码可能无法公开的棘手问题的方法。

本文介绍了如何生成转储并将其用于检查和诊断应用程序的状态。 使用Memory Analyzer,您可以检查线程,对象,包和整个数据集合,以调试Java代码问题,这些问题不仅限于内存泄漏。

快照转储类型

内存分析器当前可以使用三种转储类型:

  • IBM便携式堆转储(PHD):这种专有的IBM格式仅包含流程中每个Java对象的类型和大小以及对象之间的关系。 此转储文件格式明显小于其他格式,并且包含的​​信息最少。 但是,数据通常足以诊断内存泄漏并获得对应用程序体系结构和占用空间的基本了解。
  • HPROF二进制转储: HPROF二进制格式包含IBM PHD格式中存在的所有数据以及Java对象中保存的原始数据以及线程详细信息。 您可以查看对象内部字段中保存的值,并查看进行转储时正在执行哪些方法。 额外的原始数据使HPROF转储明显大于PHD格式的转储。 它们的大小与使用的Java堆大小大致相同。
  • IBM系统转储:使用IBM Java运行时时,可以将本机操作系统转储文件(AIX®或Linux上的核心文件,Windows®上的小型转储或z /OS®上的SVC转储)加载到内存分析器。 这些转储包含正在运行的应用程序的整个内存映像-HPROF格式的所有信息和数据,以及所有本机内存和线程信息。 这是最大,最全面的转储文件格式。

两种IBM转储类型仅在安装了Java诊断工具框架(DTFJ)插件时才可用(请参阅参考资料Memory Analyzer变体侧栏)。

表1总结了转储文件类型之间的区别:

表1.转储类型的特征摘要
转储格式 磁盘上的大概大小 对象,类和类加载器 线程详细信息 栏位名称 字段和数组引用 原始字段 基本数组内容 准确的垃圾收集根源 本机内存和线程
IBM PHD Java堆大小的20% ÿ 使用Javacore * ñ ÿ ñ ñ ñ ñ
HPROF Java堆大小 ÿ ÿ ÿ ÿ ÿ ÿ ÿ ñ
IBM系统转储 Java堆大小+ 30% ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ

*通过加载同时生成的javacore.txt文件(IBM线程转储文件)和heapdump.phd文件,Memory Analyzer可以在IBM PHD格式转储中提供线程详细信息。

HPROF和IBM系统转储格式都可以使用操作系统工具很好地压缩,通常压缩到其原始大小的20%左右。

获取快照转储

可使用不同的机制来获取每个Java运行时的各种转储,从而提供了灵活性,可以让您为涉及OutOfMemoryError之外的场景生成快照转储。 可用的机制取决于您使用的供应商的Java运行时。

先决条件

对于所有转储类型,必须确保有足够的磁盘空间用于转储,以便不会被截断。 转储的默认位置是JVM进程的当前工作目录。 对于IBM JVM,可以使用-Xdump文件命令行选项更改此设置。 对于HotSpot JVM,可以使用-XX:HeapDumpPath命令行选项对其进行更改。 请参阅相关信息的链接,相关的语法。

来自操作系统的转储可用于IBM和HotSpot JVM。 对于IBM JVM,可以使用jextract工具(与JDK一起提供)创建转储,然后将其直接加载到Memory Analyzer中。 对于HotSpot JVM,您可以使用jmap工具从核心转储中提取堆转储。 (我们将在本文后面详细讨论这两种技术。)但是,在某些操作系统上,必须确保在创建核心转储之前,该进程以足够的ulimit运行。 否则,核心转储将被截断并且分析将受到限制。 如果ulimit不正确,则必须对其进行修改并在收集转储之前重新启动该过程。 请参阅相关信息的链接,详细信息获取从AIX,Linux®的,Z / OS和Solaris系统转储。

获取快照转储:HotSpot运行时

基于HotSpot的Java运行时仅生成HPROF格式转储。 您可以选择几种交互式方法和一种基于事件的方法来生成转储:

  • 互动方式:
    • 使用Ctrl + Break :如果为正在运行的应用程序设置了-XX:+HeapDumpOnCtrlBreak命令行选项,则在Ctrl + Break事件或SIGQUIT (通常使用SIGQUIT生成)时会生成HPROF格式转储以及线程转储kill -3 ),通过控制台发送。 在某些版本上,此选项可能不可用,在这种情况下,请尝试:

      -Xrunhprof:format=b,file=heapdump.hprof
    • 使用jmap工具jmap实用工具(请参阅相关信息 ),在JDK的bin目录下交付,提供了一个选项,从正在运行的进程请求HPROF转储。 对于Java 5,请使用:

      jmap -dump:format=b pid

      在Java 6中,使用此版本,其中live是可选的,并且仅将“ live”对象写入转储文件进程ID(PID):

      jmap -dump[live,]format=b,file=filename pid
    • 使用操作系统 :使用nondestructive gcore命令或破坏性的kill -6kill -11命令来生成核心文件。 然后,使用jmap从核心文件中提取堆转储:

      jmap -dump:format=b,file=heap.hprof path to java executable core
    • 使用JConsole的工具:一个dumpHeap下提供操作HotSpotDiagnostic的MBean在JConsole中。 此操作要求生成HPROF转储。
  • 基于事件的方法:
    • OutOfMemoryError如果为正在运行的应用程序设置了-XX:+HeapDumpOnOutOfMemoryError命令行选项,则在发生OutOfMemoryError时会生成HPROF格式转储。 对于生产系统而言,理想的做法是将它安装到位,因为几乎总是需要使用它来诊断内存问题,并且不会产生持续的性能开销。 在基于HotSpot的Java运行时的较早版本中,对每个JVM运行此事件产生多少堆转储没有限制。 在较新的版本中,每个JVM运行在此事件上最多生成一个堆转储。

获取快照转储:IBM运行时

IBM运行时提供了转储和跟踪引擎,它们可以在大量基于交互和基于事件的场景中生成PHD格式或系统转储。 您也可以使用Health Center工具或以编程方式使用Java API生成交互式转储。

  • 互动方式
    • 使用SIGQUIT或Ctrl + Break:将Ctrl + Break或SIGQUIT (通常使用kill -3生成)发送到IBM运行时时,将在IBM转储引擎中生成用户事件。 默认情况下,此事件仅生成线程转储文件(javacore.txt)。 您可以使用-Xdump:heap:events=user选项生成PHD格式的转储,或使用-Xdump:system:events=user选项生成Java应用程序的系统转储。

    • 使用操作系统产生系统转储:

      • AIX: gencore (或破坏性kill -6kill -11
      • Linux / Solaris: gcore (或破坏性的kill -6kill -11
      • Windows: userdump.exe
      • z / OS: SVCDUMP或控制台转储
    • 使用IBM Java监视和诊断工具-Health Center: Health Center工具提供了一个菜单选项,用于从正在运行的Java进程中请求PHD或系统转储(请参阅参考资料 )。

  • 基于事件的方法。 IBM转储和跟踪引擎提供了一组灵活的功能,用于根据从抛出异常到执行方法的大量事件生成PHD和系统转储。 使用它们,您应该能够为要诊断的大多数问题方案生成转储:
    • 使用IBM转储引擎:转储引擎提供了大量事件,您可以在这些事件上产生PHD或系统转储。 此外,它还允许您过滤那些事件的类型,以便对何时生成转储进行更细粒度的控制。

      您可以使用-Xdump:what选项查看默认事件。 例如,您会注意到,JVM中的前四个OutOfMemoryError异常产生了heapdump.phd和javacore.txt。

      要收集更多数据,可以在OutOfMemoryError异常上生成系统转储而不是堆转储:

      -Xdump:heap:none -Xdump:java+system:events=systhrow,
       filter=java/lang/OutOfMemoryError,range=1..4,request=exclusive+compact+prepwalk

      一些异常,例如NullPointerException ,在大多数应用程序中通常是由大量代码生成的。 这使得很难在感兴趣的特定NullPointerException上生成转储。 为了帮助您更具体地了解将在哪个异常上生成转储,为“ throw”和“ catch”事件提供了额外的过滤级别,使您可以分别指定throwing和catching方法。 为此,您可以添加#分隔符,然后根据需要添加throwing或catch方法。 例如,当bad()方法抛出NullPointerException时,此选项会产生系统转储:

      -Xdump:system:events=throw,
             filter=java/lang/NullPointerException#com/ibm/example/Example.bad

      catch()方法捕获到NullPointerException时,此选项将产生系统转储:

      -Xdump:system:events=catch,
             filter=java/lang/NullPointerException#com/ibm/example/Example.catch

      除了对事件进行过滤之外,您还可以指定要在其上生成转储的一系列事件。 例如,此选项仅在第五次出现NullPointerException产生转储:

      -Xdump:system:events=throw, filter=java/lang/NullPointerException,range=5

      此选项使用范围仅在第二,第三和第四次出现NullPointerException产生转储:

      -Xdump:system:events=throw, filter=java/lang/NullPointerException,range=2..4

      表2总结了最有用的事件和过滤器:


      表2.可用的转储事件
      事件 描述 可用过滤
      gpf 一般保护故障(崩溃) -Xdump:system:events=gpf
      user 用户生成的信号( SIGQUIT或Ctrl + Break) -Xdump:system:events=user
      vmstop 虚拟机关闭,包括对System.exit()调用 退出码 -Xdump:system:events=vmstop,filter=#0..#10
      在VM关闭时生成系统转储,退出代码在010之间。
      load 类负荷 班级名称 -Xdump:system:events=load,filter=com/ibm/example/Example
      加载com.ibm.example.Example类时,生成系统转储。
      unload 类卸载 班级名称 -Xdump:system:events=unload,filter=com/ibm/example/Example
      卸载com.ibm.example.Example类时,生成系统转储。
      throw 引发异常 异常类名称 -Xdump:system:events=throw,filter=java/net/ConnectException
      生成ConnectException时生成系统转储。
      catch 被捕获的异常 异常类名称 -Xdump:system:events=catch,filter=java/net/ConnectException
      捕获ConnectException时生成系统转储。
      systhrow JVM将抛出Java异常。 (这与throw事件不同,因为它仅针对JVM内部检测到的错误情况才触发。) 异常类名称 -Xdump:system:events=systhrow,filter=java/lang/OutOfMemoryError
      生成OutOfMemoryError时生成系统转储。
      allocation 分配了Java对象 分配对象的大小 -Xdump:system:events=allocate,filter=#5m
      分配大于5MB的对象时,生成系统转储。
    • 使用IBM跟踪引擎:跟踪引擎允许在应用程序中运行的任何Java方法的方法入口或出口处触发PHD和系统转储。 通过对控制IBM跟踪引擎的-Xtrace命令行选项使用trigger关键字,可以完成此任务。 触发器选项的语法为:
      method{methods[,entryAction[,exitAction[,delayCount[,matchcount]]]]}

      在调用Example.trigger()方法时,向应用程序添加以下命令行选项会产生系统转储:

      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,sysdump}

      调用Example.trigger()方法时,此命令行选项将生成PHD转储:

      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,heapdump}

      但是,建议您设置一个范围,以免在每次调用该方法时都不创建转储。 本示例忽略对Example.trigger()的前五个调用,然后触发一个转储:

      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,sysdump,,5,1}

      请注意,在此示例中, exitAction使用空术语,因为我们仅在方法条目上触发转储。
  • 编程方法: IBM运行时还提供了带有javaDump( ), heapDump()systemDump()方法的com.ibm.jvm.Dump类。 它们分别生成线程转储,PHD转储和系统转储。

使用内存分析器获取转储

除了运行时自身提供的获取转储的方法外,Memory Analyzer还提供了一个Acquire Heap Dump选项,如图1所示,它使您能够从运行在同一台计算机上的Java进程中触发并加载快照转储。作为内存分析器:

图1.在内存分析器中使用“获取堆转储”功能
该屏幕截图显示了内存分析器中的“获取堆转储”功能

在基于HotSpot的运行时,内存分析器使用jmap生成转储。 对于IBM运行时,转储使用Java“后期附加”功能和编程API生成。 该功能需要Java 6 SR6,因为早期版本不包含“后期附加”功能。

后处理要求

对于IBM系统转储,必须使用JDK随附的jextract工具对转储进行后处理:

jextract core

理想情况下, jextract在产生转储的同一台物理计算机上运行,​​使用产生转储的同一JDK安装中的jextract ,并具有与运行java进程的相同库的读访问权限。 鉴于jextract会消耗大量CPU周期来处理转储,因此在某些生产系统中这可能是不可接受的。 在这种情况下,应该在最接近的匹配系统(例如生产前测试系统)上处理转储。 Java运行时的服务刷新(SR)和修订包(FP)版本应匹配。

jextract生成一个ZIP文件,该文件包含原始核心转储,转储的经过处理的表示形式,Java可执行文件以及java进程使用的库。 您可以在运行jextract后删除原始(未压缩)核心转储。 ZIP文件是您应该加载到Memory Analyzer中的文件。

您可以提取从一个PHD转储jextract通过装载ZIP进入编辑系统转储jdmpview和执行heapdump命令(请参阅相关的主题 )。

使用内存分析器分析问题

内存分析器可以通过查找应用程序的某些区域来诊断OutOfMemoryError ,这些区域要么泄漏内存,要么对可用内存的占用空间太大。 内存分析器会自动进行泄漏检测并生成“泄漏可疑”报告(请参阅参考资料 )。

HPROF和IBM系统转储中可用的其他数据,尤其是字段名称和字段值-以及Inspector视图和对象查询语言(OQL)的功能-还可以诊断比以下类型更广泛的问题类型“什么在使用所有内存?”。 例如,您可以确定集合的占用率和负载因数,以查看它们的大小是否有效,或者查看与ConnectException关联的主机名和端口,以查看应用程序试图创建的连接。

使用检查器查看对象中的字段

在“内存分析器”中选择任何对象时,“检查​​器”视图将显示与该对象有关的可用信息,包括类层次结构,属性和静态信息。 “属性”面板显示与对象关联的实例字段和值,而“静态”面板显示与类关联的静态字段和值。

图2所示的Inspector视图提供了一个简单的java.net.URL对象,您可以查看有关该对象的详细信息,包括URL所适用的协议类型和目标:

图2. Inspector视图中的Statics,Attributes和Class Hierarchy面板
屏幕快照显示了“检查器”视图中的三个面板

图2中 ,您可以在“属性”面板中看到URL对象引用位于本地文件系统上(由path和file字段指定的位置)的JAR文件(协议字段)。

使用OQL对对象运行查询

OQL可用于使用类似于SQL的自定义查询来查询转储。 该主题本身可能只是一篇文章,因此我们仅重点介绍一些示例。 有关更多详细信息,请查阅Memory Analyzer中提供的OQL帮助内容。

OQL对于遵循从一组对象的传出引用和字段到特定字段的路径特别有用。 例如,如果类A的字段fooB类型,而类B的字段barString ,则查找所有这些String的简单查询将是:

SELECT aliasA.foo.bar.toString()
FROM A aliasA

我们给类A别名aliasA ,然后在SELECT子句中引用它。 此查询严格仅从类A实例中选择。 如果要从类A所有实例以及任何子类中进行选择,则可以使用:

SELECT aliasA.foo.bar.toString()
FROM INSTANCEOF A aliasA

这是DirectByteBuffer的更复杂的示例:

SELECT k, k.capacity
FROM java.nio.DirectByteBuffer k
WHERE ((k.viewedBuffer=null)and(inbounds(k).length>1))

在这种情况下,我们想要获取任何DirectByteBuffer的容量字段,该字段给出该对象持有的本机内存。 我们还希望过滤掉任何DirectByteBuffer S作空viewedBuffer场(因为这些都只是为其他视图DirectByteBuffer S)和一个以上的入站引用(所以我们不看那些未决DO清理他们的虚引用—也就是说,我们只需要“实时” DirectByteBuffer )。

在视图或转储之间进行比较

使用内存分析器,您可以比较查询生成的表。 这些表可以来自同一转储,让您查看一个视图中的String对象是否存在于另一视图中看到的集合对象中,也可以跨不同的转储,让您查找数据的变化,例如对象集合的增长。

要进行比较,请将相关表添加到“比较篮”,然后请求比较篮中的条目。 首先,在Navigation History中找到并选择表的条目,然后从上下文菜单中选择Add to Compare Basket ,如图3所示:

图3.将表从Navigation History视图添加到Compare Basket
屏幕截图显示了内存分析器中的“添加到比较篮”功能

在“比较购物篮”中有两个条目之后,可以使用面板右上角的“比较结果”按钮(红色感叹号)运行比较,如图4所示:

图4.比较比较篮中条目的结果
屏幕截图显示了内存分析器中的“比较结果”功能

占用空间和存储效率

内存分析器的另一个重要用途是查找哪些组件正在使用大部分堆,即使在没有内存泄漏的情况下也是如此。 如果可以减少内存使用量,则可以提高系统的容量或性能,从而允许更多的会话或更少的垃圾收集时间。

顶级组件报告是第一步。 它按系统中的组件划分内存使用情况,分析每个组件中的使用情况,并寻找浪费的做法。 可以说,由另一个对象控制(保留)另一个对象的对象由该控制者拥有 。 “顶部组件”报告列出了不属于另一个对象的所有对象。 这些是堆的主要控制者。 然后,使用对象的类由类加载器将顶级控制者划分开,并将所有这些顶级控制者和它们所拥有的对象分配给适当的类加载器。 您可以通过在报告中选择一个类加载器来打开一个新的特定于类加载器的组件报告来进一步分析。

对于每个组件,都会分析Collections对象。 如java.util.*所示,Collections类为程序员节省了很多时间,它提供了经过测试的列表,集合和映射的实现。 一般的应用程序可以包含数百万个集合,因此集合中的浪费空间可能非常大。

空集合是浪费内存的常见原因之一。 ArrayListVectorHashMapHashSet的创建具有默认大小的后备数组,该数组可能包含10个条目,可以随时保存条目。 在应用程序中创建集合但没有存储对象的情况令人惊讶地常见。 这会Swift消耗内存。 例如,对于100,000个空集合,仅支持数组就可以消耗100,000 *(24 + 10 * 4)字节= 6MB。

空集合报告查看标准集合类及其扩展,并按集合大小分析它们。 然后,它为每个集合生成一个表,该表按集合的大小排序,最频繁的大小在前。 如果集合类型的大部分实例为空,则该报告会将其标记为可能的内存浪费。

一种解决方案是延迟分配集合,直到需要插入一个条目为止。 另一个方法是分配一个默认大小为0或1的集合,如果需要,可以使其增长,但需要一些运行时成本。 第三是在初始化阶段完成后将集合调整为适当大小。

一个相关的领域是只有几个条目和大量浪费空间的集合。 “集合填充率”部分针对每种集合类型显示具有特定填充率的该集合的实例数。 这显示出具有很大空白空间的集合。

字符串重复

字符串和字符数组在典型的业务应用程序中占用大量空间,因此它们是另一个值得分析的领域。 组件报告的此部分分析常见内容的字符串。 字符串是不可变的。 VM规范保证具有相同值的字符串常量使用相同的实例。 动态构建的字符串没有这种保证,例如,通过从数据库或磁盘中读取具有相同值的数据而构建的两个String ,将具有单独的实例和单独的后备字符数组。 如果保留这些字符串,那么这可能很重要。

您可以通过使用String.intern()或维护用户哈希集或哈希映射来解决此问题。

浪费的char数组

通过建立共享原始字符数组的新String ,以Java语言实现String.substring( )。 如果仍然需要原始字符串,这将非常有效。 如果只需要一个小的子字符串,那么-因为保留了整个字符数组-浪费了一些空间。 “在字符数组中浪费”查询显示仅由字符串引用的字符数组中浪费的空间量。

Eclipse捆绑包和类加载器层次结构

现代应用程序通常基于类加载器分为多个组件,以在应用程序的各个部分之间提供一定程度的隔离。 可以通过停止使用一个组件类加载器并使用新的类加载器加载组件的新版本来更新组件。 随着时间的推移,假定应用程序不包含对类或对象或类加载器的外部引用,则可以通过垃圾回收释放旧版本。

Class Loader Explorer查询显示了系统中的所有类加载器,因此适用于所有应用程序。 它显示了由类加载器加载的类以及类加载器的父链,以便可以理解类加载问题。 通过检查,您可以查看是否存在一个类加载器的多个副本。 如果类加载器几乎没有定义类的实例,则该类加载器很可能是空闲的。

重复类查询显示了由多个类加载器加载的类名称。 这可能表明类加载器内存泄漏。 它仅需引用系统中其他位置(例如注册表)中保存的对象,即可发生类加载器泄漏。 该对象保留对其类的引用,对类加载器的引用,对所有已定义类的引用。

常见的类加载框架是OSGi框架。 一种实现是Eclipse Equinox,用于基于Eclipse的应用程序以分隔插件,并且还用于WebSphere®Application Server 6.1和更高版本。 尝试了解应用程序的状态时,了解所有捆绑软件的状态很有用。 如图5所示,Eclipse Equinox Bundle Explorer查询就是这样做的:

图5. Eclipse Bundle Explorer
屏幕快照显示了Bundle Explorer视图

系统或HPROF转储具有所有对象和字段。 捆绑包浏览器显示系统中的所有捆绑包,以及它们的状态和依赖关系,依赖关系和服务。 它可以显示异常活跃的捆绑包,因此会使用更多资源。

线程数据使用

表1所示 ,转储可以包括线程详细信息,这些线程详细信息可以提供对转储时正在发生的事情的独特见解。 这可以包括所有活动线程堆栈,每个线程的所有框架,最重要的是,这些框架上的部分或全部活动Java局部语言。

线程概述视图

如图6所示,“线程概述”视图显示了JVM中的每个线程以及该线程的各种属性,例如其保留的堆大小,上下文类加载器,优先级,状态和本机ID:

图6.线程概述
该屏幕快照显示了“线程概述”视图

保留堆大小在OutOfMemoryError期间本身没有发生Java堆问题的情况下特别有用,而线程保留堆的总和“太多”。 在这种情况下,JVM的大小可能不足,线程池的大小可能太大,或者线程的平均或最大Java堆“负载”太大。

线程堆栈视图

如图7所示,“线程堆栈”视图显示了每个线程,其堆栈,堆栈框架以及这些堆栈框架上的Java本地语言:

图7.线程堆栈视图
该屏幕快照显示了“线程堆栈”视图

图7的示例中,扩展了一个类型为java.lang.Thread且名称为main (简单命令行程序中的主线程)的线程。 将显示该线程的每个堆栈框架,并且具有可用Java本地语言的那些框架都是可扩展的。 在这种情况下,已将String作为参数从Play.method1Play.method2 ,并且字符串user1的内容以红色圆圈突出显示。 您可以想象基于每个线程堆栈帧中发生的事件以及基于哪些对象,能够对转储时发生的事件进行重构或逆向工程的能力。

请注意,由于运行时优化,并非所有相关对象(例如方法参数或对象实例)都将可用(尽管这些对象将在转储中),但通常会“主动处理”那些对象。

异常分析

当应用程序中生成异常时,其他复杂情况会使分析异常原因更加困难。 这种困境的两个例子是:

  • 使用日志记录机制意味着异常丢失或异常消息被删除。
  • 异常是生成一条包含足够信息的消息。

在第一种情况下,异常消息或整个异常都将完全丢失,从而很难知道问题是否存在或难以获得有关该问题的基本信息。 在第二种情况下,已记录了异常,并且异常消息和堆栈跟踪可用,但是它不包含解决异常原因的必要信息。

由于Memory Analyzer可以访问对象内部的字段,因此可以从异常对象中找到异常消息。 在某些情况下,还可以提取原始异常中没有的其他数据。

在快照转储中查找异常

定位快照转储中存在的异常的一种方法是使用内存分析器中的OQL功能来定位转储中的目标对象。 例如,此查询查找所有异常对象:

SELECT * 
FROM INSTANCEOF java.lang.Exception exceptions

下一个查询产生所有异常的列表,您可以使用Inspector视图查看每个异常内的字段。 知道包含异常消息的字段是detailMessage字段,您还可以修改查询以直接提取异常消息并将它们立即显示为结果表的一部分:

SELECT exceptions.@displayName, exceptions.detailMessage.toString() 
FROM INSTANCEOF java.lang.Exception exceptions

前面的查询产生图8所示的输出:

图8. OQL查询的异常输出,包括异常消息
屏幕快照显示了OQL查询的输出

图8显示了应用程序中仍然存在的每个异常,以及抛出该异常时将显示的消息。

提取与异常有关的其他信息

尽管从转储中找到异常对象可以使您恢复异常消息,但有时异常消息过于笼统或含糊,无法使您理解问题的原因。 一个很好的例子是java.net.ConnectException 。 尝试建立与不接受连接的主机的套接字连接时,会出现以下消息:

java.net.ConnectException: Connection refused: connect
     at java.net.PlainSocketImpl.socketConnect(Native Method)
     at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:352)
     at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:214)
     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:201)
     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:377)

     at java.net.Socket.connect(Socket.java:530)
     at java.net.Socket.connect(Socket.java:480)
     at java.net.Socket.(Socket.java:377)
     at java.net.Socket.(Socket.java:220)

如果您有权访问创建套接字的代码,并且可以从代码中看到正在使用的主机名和端口,则此消息就足够了。 如果是更复杂的代码,其中主机名和端口值是由于它们是从外部来源(用户输入值,数据库等)获得的,因此可能会发生更改,因此该消息无法帮助您理解为什么连接被拒绝了。

堆栈跟踪应包括一个包含有用数据的套接字对象,如果可以使用Memory Analyzer在快照转储中找到该套接字对象,则可以找出哪个主机名和端口拒绝了该连接。

最简单的方法是在引发异常时生成转储。 可以使用以下-Xdump选项集在IBM运行时上完成此操作:

-Xdump:system:events=throw,range=1..1,
       filter=java/net/ConnectException#java/net/PlainSocketImpl.socketConnect

此选项在由PlainSocketImpl.socketConnect()方法生成的第一次出现ConnectException生成IBM系统转储。

将生成的快照转储加载到Memory Analyzer之后,我们可以使用Open Query Browser> Java Basics> Thread Stacks选项在线程的堆栈跟踪中列出线程和与每个方法关联的对象。

By expanding the current thread and the method frames in the thread, you can look at the objects associated with those methods. In the case of a java.net.ConnectException , the most interesting method is java.net.Socket.connect() . Expanding this method frame shows a reference to a java.net.Socket object in memory. This is the socket connection we were trying to make.

When the Socket object is selected, the fields are shown in the Inspector view, as you can see in Figure 9:

Figure 9. Inspector view for the Socket object
Screen shot showing the Inspector view for a Socket object

The information in Figure 9 isn't too useful, because the real implementation of the Socket is in the impl field. You can inspect the contents of the impl object by either expanding the Socket object and selecting the impl java.net.SocksSocketImpl line in the main panel, or by right-clicking on the impl field in the Inspector view and selecting Go Into . Now the fields for SocksSocketImpl are visible in the Inspector view, as shown in Figure 10:

Figure 10. Inspector view for the SocksSocketImpl object
Screen shot showing the Inspector view for a Socket Impl object

The view shown in Figure 10 gives access to the address and port fields. In this case, the port is 100 , but the address field points to a java.net.Inet4Address object. Following the same process to look into the fields of the Inet4Address objects shows the results displayed in Figure 11:

Figure 11. Inspector view for the Inet4Address object
Screen shot showing the Inspector view for a Inet4Address object

You can see that the hostName is set to baileyt60p .

技巧和窍门

Here are a few tips and tricks that may be useful:

  • Don't forget that Memory Analyzer itself may run out of memory. For the Eclipse MAT, edit -Xmx in the MemoryAnalyzer.ini file. For the ISA version, edit the ISA Install /rcp/eclipse/plugins/com.ibm.rcp.j2se.../jvm.properties file.
  • If you're still running out of memory on a 32-bit version of Memory Analyzer, use the 64-bit version of Eclipse MAT or try the headless mode (see Related topics ). (The ISA tool currently does not currently support 64-bit.)
  • Memory Analyzer writes "swap" files in the directory of the dump, which lessens the dump's reload time. These files can be zipped, sent to another machine, and placed in the same directory as the dump, making a complete reload of the dump unnecessary.
  • If a dump's size does not correlate with the garbage collector at the time of the dump, consult the Unreachable Objects Histogram link in the Overview tab. The Java heap may have had a lot of garbage (for example, if a tenured collection hadn't run for some time) that Memory Analyzer removed.
  • If two objects A and B do not have direct references to each other, but both have outgoing references to some set of objects C , then the Retained Heap of the set C will not be included in either of the retained sets of A or B , but rather in the retained set of the dominator of both A and B . In some situations, B may be temporarily observing the set C , which is actually the progeny of A . In this case, you can right-click on A and select Java Basics > Customized Retained Set and use the address of B as the exclude ( -x ) parameter.
  • You can load multiple dumps at once and compare them. Open the Histogram of the more recent dump, click the Compare button at the top, and choose the baseline dump.
  • When you are exploring a reference tree, be aware that references can refer, directly or indirectly, back to a "parent" reference, so that you could enter an exploration loop or cycle (for example, in a linked list). Be aware of the object addresses. Also, be aware that if the class name of an object is preceded by the word class , that you are exploring the static instance of that class.
  • The String value displayed in most views is limited to 1,024 characters. If you need the whole String , right-click on the object and select Copy > Save value to file .
  • Most views have an export option, and most HTML results are created on the file system, so that data can be exported for sharing or further transformation. Relatedly, you can press Ctrl+C on any selection of rows in a grid to copy a textual representation of those rows to your clipboard.

Memory Analyzer was originally developed as "a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption," as it's described on Eclipse.org. But its capabilities clearly stretch far beyond that description. In addition to their role in diagnosing "normal" memory problems, snapshot dumps can be used as an alternative to, or in addition to, other types of problem-determination techniques such as tracing and patching. Particularly with HPROF dumps and IBM system dumps, Memory Analyzer gives you memory contents such as primitives and the field names from the original source code. Using the various views covered in this article, you can explore or reverse-engineer the problem at hand, including overall footprint and memory efficiency, Eclipse bundles and classloader relationships, thread data usage and stack frame locals, exceptions, and more. OQL and the Memory Analyzer plug-in model also allow you to inspect the dump more easily using a query language and programmatic methods that can help in automating common analysis.


翻译自: https://www.ibm.com/developerworks/opensource/library/j-memoryanalyzer/index.html

gdb调试转储文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值