在java调试会话期间查找大字符串分配
分析堆转储后,我发现分配了大约30MB的字符串(单个字符串为30MB)。在java调试会话期间查找大字符串分配,java,string,Java,String,分析堆转储后,我发现分配了大约30MB的字符串(单个字符串为30MB)。 有没有办法在调试应用程序时设置断点,以便找到分配这些巨大字符串的代码? 由于在应用程序运行期间分配了数千个字符串,所以不可能只在每个字符串分配上设置断点。 我认为条件断点也会太慢。 如果可能的话,我想检查这些字符串内容,以了解这些分配的来源。 例如,它们可能是web服务调用的结果,web服务调用通常使用少量数据进行调用,但在极少数情况下使用大量输入进行调用(我希望找到这些情况) 将java.lang.String的源代码从
有没有办法在调试应用程序时设置断点,以便找到分配这些巨大字符串的代码? 由于在应用程序运行期间分配了数千个字符串,所以不可能只在每个字符串分配上设置断点。 我认为条件断点也会太慢。
如果可能的话,我想检查这些字符串内容,以了解这些分配的来源。
例如,它们可能是web服务调用的结果,web服务调用通常使用少量数据进行调用,但在极少数情况下使用大量输入进行调用(我希望找到这些情况)
java.lang.String
的源代码从JDK源代码复制到
计划java.lang.String
的现有实例变量)
private void checkSize(){
如果(计数>1000000)//1MB
系统输出打印项次(计数);
}
java.lang.String
以在每个构造函数的末尾调用此方法checkSize()
java.lang.String
添加到bootstrap类路径我会尝试使用条件断点,即使这意味着让应用程序运行一两天。至少在它运行时,您可以继续进行其他操作。不管怎样,任何其他解决方案都可能需要一两天才能实现
否则,您可以使用AspectJ将切入点添加到字符串构造函数中,并使用切入点记录消息、引发异常等。这与条件断点基本相同,但应该运行得更快。尽管您明确要求调试会话,我假设这主要是为了解决实际问题:分配了大字符串,而您不知道这在哪里发生 分配可以通过以下方式进行跟踪。您可以启动jVisualVM和您的程序,并将jVisualVM连接到您的程序 如果这不符合你的需要,我可以删除这个答案。否则,您可以这样做: 在“探查器”选项卡中,您可以选中右上角的“设置”复选框,然后选择“内存设置”选项卡。您可以在此处设置“记录分配堆栈跟踪”复选框: 然后,按下顶部的“内存”按钮后,探查器将收集有关字符串分配的信息。退出应用程序后(或拍摄快照后),您可以检查记录的堆栈跟踪,以找到分配大字符串的方法—在本例中为
method4
:
这可能很接近:继续监视字符串对象的堆,一旦看到spike,立即执行线程转储我猜理论上JVM可以在调试模式下运行,记录创建每个对象的
新的的位置。。。但我不知道是否有这样的JVM。@Raedwald字符串是不可变的;只要有if(length()>300000)/*断点*/在构造函数中,当我使用“大字符串”时,我遇到了大量内存消耗的问题。在Java6和更早版本中,保存在集合中的子字符串(几个字符)
可能会占用大量空间。我喜欢在字符串构造函数中使用条件断点的方法但是OP建议这是不可行的,因为断点的开销。这会显示堆栈跟踪的总内存还是分配的巨大字符串的特定实例?(我正在寻找一个分配了30MB数据的单字符串实例)不完全清楚“特定实例”是什么意思。您将看不到字符串的内容。但是(如第二个屏幕截图所示),您将收到分配堆栈跟踪的可浏览视图。默认情况下,它们按字节数排序。因此,通过展开最大char[]
chunk的前3级,您可能会找到“大型”分配的位置。(再次强调:这只是一种可能带来所需见解的方法,但我不能保证它适用于您的应用案例)