Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find large strings allocation during java debug session

Tags:

java

string

After analyzing a heap dump I found that there were some 30MB strings allocated (single string of 30 MB).
Is there a way to set a break point while debugging the application so I can find the code which allocates these huge strings? Since thousands of strings are allocated during application run it isn't possible just putting a break point on each string allocation. I believe conditional break point will be too slow as well.
If possible I would want to exam those strings content to understand the origin of these allocation.
For example they may be a result of a web service call which usually is called with small amount of data but in rare cases with huge input (which are the cases I want to find).

like image 734
Avner Levy Avatar asked Aug 18 '14 06:08

Avner Levy


3 Answers

Although you explicitly asked for a debug session, I assume that this was mainly an attempt to solve the actual problem: Large strings are allocated, and you don't know where this happens.

The allocations can be traced with jVisualVM. You can start jVisualVM and your program, and connect the jVisualVM to your program.

If this does not suit your needs, I can delete this answer. Otherwise, here's how you can do it:

In the "Profiler" tab you can check the "Settings" checkbox in the upper right, and select the "Memory Settings" tab. There you can set the "Record allocation stack traces" checkbox:

StringAlloc01

Then, after pressing the "Memory" button at the top, the profiler will collect the information about the string allocations. After the application has exited (or after a snapshot has been taken), you can examine the recorded stack traces to find the method that allocates the large string - in this example, method4:

StringAlloc02

like image 198
Marco13 Avatar answered Nov 04 '22 07:11

Marco13


  1. Copy the source code of java.lang.String from JDK sources to your project

  2. Create a method in your String.java like below (count is an existing instance variable of java.lang.String)

    private void checkSize(){ if(count>1000000) //1MB System.out.println(count); }

  3. Edit java.lang.String to call this method checkSize() at the end of every constructor

  4. Add breakpoint at the line System.out.println(count);

  5. Add the new java.lang.String to bootstrap classpath

  6. This breakpoint will break only when a String of size > 1MB gets created

like image 28
Rajeev Sreedharan Avatar answered Nov 04 '22 09:11

Rajeev Sreedharan


I'd try the conditional breakpoint, even if it meant leaving the app running for a day or two. At least then you can get on with something else while it is running. And any other solution is likely to take a day or two to implement anyway.

Failing that, you could using AspectJ to add pointcut into the String constructors and use that to log a message, throw an exception etc. This is basically the same as a conditional breakpoint but should run more quickly.

like image 30
matt helliwell Avatar answered Nov 04 '22 08:11

matt helliwell