Runtime memory increase when migrating a Swing application from Java 6 to Java 7 Update 11
Asked Answered
S

3

7

We are facing a performance issue once the Java Swing application is moved from Java 6 32 bit to Java 7 32 bit update 11. Can anyone provide some clue on this ?

The application is using Java Web-start technology and the server is Tomcat 7. The client application is consuming 1GB of memory, so the screen is freezing out.

We are exchanging serialized objects, following is the code:

Object object = connection.sendCommand(command); // exchanging serialized object            

public class ConnectionImpl implements Connection {
    public Object sendCommand(Command command) throws Exception {
        URL url = new URL(System.getProperty("serverUrl"));
        URLConnection connection = url.openConnection();
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setUseCaches(false);
        oos = new ObjectOutputStream(new BufferedOutputStream(connection
                    .getOutputStream()));
        oos.writeObject(command);
        oos.flush();
        InputStream inputStream = connection.getInputStream();
        ZipInputStream zip = new ZipInputStream(inputStream);
        if (zip.getNextEntry() != null) {
            ois = new ObjectInputStream(zip);
            object = ois.readObject();
        }
        zip.close();
    }
}

// The serialized class
public class CommandImpl implements Command, Serializable {
    private String serviceName;
    private String methodName;
    private Map<String, Object> parameterMap;

// followed by getter & setters
}
  • Client Machine: Windows 7 32 bit, Java 7 update 11 32 bit
  • Server Machine: Windows 64 bit 2008 R2 Enterprise Server, Java 7 update 11 64 bit

There is no change in the code only the JVM is updated.

I have taken the memory snapshot for JDK 1.6 and JDK 1.7 using Java VisualVM, following is the link to rar file which contains the snapshots:

Memory Snapshots using Java VisualVM Heap Dump using Java VisualVM

The NetBeans IDE provides an option to migrate the code from Java 6 to Java 7. Following is the link regarding this:

https://netbeans.org/kb/docs/java/editor-inspect-transform.html#convert

Will it be a good option for migrating the entire source code from Java 6 to Java 7 without any issue? Or anyone feels that it might create some issue ? And if we do so, whether we can solve this performance issue up-to some extend?

Scratchy answered 7/6, 2013 at 11:43 Comment(9)
"Can anyone provide some clue on this" <-- and what about [insert your favorite search engine here]? Also, you tell nothing about the environment apart from the JVM versions; what about the OS?Boathouse
Also: What components cause that loss of performance? Can you somewhat narrow it down to a scrren with only certain components?Wreak
Is 1GB memory more than before? If so, did you also change to a 64bit JVM?Betthezel
Have you tried recompiling the apps with Java 7?Ringside
@Ringside Yes, we have complied using java 7 update 11 (64 bit)Scratchy
Are you exchanging serialized objects, DataInput/OutputStreams? RMI? Help the readers by providing more hints. Maybe a good moment for QA: try FindBugs.Binnacle
@Ryan This is the first time that I am working on performance issue and new to any tools like VisualVM, So I took a snapshot before loging in to the application and after performing some common functionalities for both JDK 1.6 and JDK 1.7. Snapshot before loging in to application are: snapshot-JDK1.6BeforeLogin.nps: App running in JDK 1.6 snapshot-JDK1.7BeforeLogin.nps: App running in JDK 1.7 Snapshot after performing same activities: snapshot-JDK1.6Final.nps: App running in JDK 1.6 snapshot-JDK1.7Final.nps: App running in JDK 1.7Scratchy
@Scratchy The files have the same md5 checksum: 7d39d4f9fb6e5decc74ae24c37bc3a4e *./snapshot-JDK1.6BeforeLogin.nps 7d39d4f9fb6e5decc74ae24c37bc3a4e *./snapshot-JDK1.6Final.nps 088137e208f124f1539b528cb19cb2cb *./snapshot-JDK1.7BeforeLogin.nps 088137e208f124f1539b528cb19cb2cb *./snapshot-JDK1.7Final.npsWatchband
You say that the screen is freezing, is it because you are running out of memory? Make sure the console is visible and/or writing to a log file. If it is running out of memory you should get a OutOfMemoryError. If so what does the stacktrace die on? Other reasons why the UI could be freezing is performing a synchronous (and long running) action on the EventQueue.Consumption
W
6

The ObjectOutputStream oos gets constructed in the method but it doesn't look like you ever close it. Closing the stream will free memory.

When does ObjectOutputStream get garbage collected? ObjectOutputStream and ObjectInputStream keep read and written objects in memory. That will look like a memory leak.

I'd suggest you add finally blocks to be sure the Streams get closed. I can't tell what the lifetime of the serialized objects is from what you posted but you might benefit from using the readUnshared and writeUnshared methods.

You wrote:

Will it be a good option for migrating the entire source code from Java 6 to Java 7 without any issue? Or anyone feels that it might create some issue ? And if we do so, whether we can solve this performance issue up-to some extend?

You won't benefit from using a tool to update the code to 1.7. If you did that you would no longer be able to run your code in 1.6. I recommend running Netbean's "Performance" inspections. Also, I highly recommend running FindBugs against your codebase.

Heapdumps

  • The jdk 1.7 dump was taken of the heap when 53M was used.
  • The jdk 1.6 dump was taken when 61M were used.

The heapdumps you posted aren't that helpful because it looks like they were taken before memory was an issue. You need to take a heapdump while the system is using lots of memory so that you can examine the dump and find out where the memory is being used.

Add the -XX:+HeapDumpOnOutOfMemoryError jvm option. With this option java will automatically take its own heapdump when it runs out of memory.

Snapshots

** Although your snapshots archive has four files in it, two of the files are duplicates with different names. Look at the sizes and the checksums and you will see they are the same. **

The snapshots are more informative but they also seem to have been taken before much memory was used.

The 1.7 snapshot has many more String instances.

The 1.6 snapshot looks like this: visualvm iamge

The 1.7 snapshot looks like: enter image description here

String.substring no longer shares an underlying character array. That can be a pretty big difference in code that does lots of String manipulation.

Those char[] hold the actual data in your String objects. I would take a closer look at what objects hold Strings and how those Strings get constructed.

Watchband answered 11/6, 2013 at 0:33 Comment(1)
Will it be a good option for migrating the entire source code from Java 6 to Java 7 without any issue? Or anyone feels that it might create some issue ? And if we do so, whether we can solve this performance issue up-to some extend?Scratchy
M
5

I think there are too many possible explanations and too little hard evidence in the Question to say what the problem is.

I suggest that you:

  1. increase the heap size to get it to the point where application starts on Java 7, then
  2. run a memory profiler on the Java 7 and Java 6 versions to figure out why Java 7 is using significantly more memory.

Notes:

  • Going from a Java 6 32 bit to Java 7 64 bit client-side execution platform, would be enough to explain the increased memory usage. (But apparently the client side OS is 32 bit, so that eliminates that explanation, though your Question actually contradicts itself on this point ...)
  • Recompiling using a Java 7 compiler (32 bit or 64 bit) is unlikely to make any difference.
  • The server platform is unlikely to be relevant.
Mok answered 7/6, 2013 at 11:59 Comment(0)
P
2

Seems Quite Likely and Normal

You say:

There is no change in the code only the JVM is updated.

Except than even if there's no change in your code, there's potentially quite a lot of changes in:

  • the JVM's own operating code,
  • the Class Library's code.

JVM's Implementation Changes

It might use more memory for its process already. This isn't exactly something that would be covered by the JVM spec, and you can't do much about that.

Class Library's Code

Its static footprint might be bigger, so as the JVM loads its normal libraries it would already consume some of the allocated memory. But, more likely, it's also your usage of it thas as an impact. Say a class you use often as changed its internal implementation and uses more memory than in 1.6.x, and it means your program now uses more memory for every instance of that object that you hold.

So, you could have quite varying memory consumption figures here. For instance, the hashing implementation for hash maps as changed (though that shouldn't change how much memory it uses in its final state), some basic data structures may have different internals (I hope not), and more complicated components may be a lot more different than this internally (loggers, utils, data and event processors, etc...).

Anything that changed in the classlib and that you use or that any library you reference yourself is using could explain that difference and be enough for you to go overboard.

Possible Ways to a Resolution

Profile!

Take memory snapshots of your program after startup using both setups and compare the consumption for each class. See what changed, what can be re-worked, trimmed, substituted with something else or dumped entirely.

Throw More Resources at the Problem

That's the no-brainer solution, but it's often a good-enough solution, if it's not an operational problem for you or the customers using your program.

Buy more RAM, and increase your JVM's memory settings.

Prepositive answered 7/6, 2013 at 12:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.