I'm making a fast-paced realtime Android game, and everything works great, but the first couple of seconds when the game starts are very laggy because the garbage collector is cleaning up after the loading thread. Sure, the player could wait a few seconds (like 10+ sec) because after its done it starts running perfectly smooth, but that looks really ugly and feels like the game is buggy.
Is there a way (or technique) to tell when its safe to start the game so the garbage collector won't start going crazy as soon as the real-time part begins? the big fat loading thread can't be reduced much without breaking things.
This seems like a case where System.gc() might help. It tells the system that this would be a good time to collect garbage. According to the documentation,
When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.
The docs also say, though, that the method "suggests" that objects be collected -- that is, there's no guarantee it'll help, particularly if you still have some references squirreled away. If it does work, it'll only collect objects that are not reachable at all from the running code, including the runtime. (That loader thread, for example, is not eligible for collection til it's finished running and your code has no more references to it.)
You can run System.gc() right before you start the game to manually force the garbage collector to run (and, according at least to the official JavaDoc here, finish before returning from this method call). However, the GC in general is nondeterministic and there is no guarantee that it will not be run again or, for that matter, that the call to System.gc() will do anything at all.
If you looked into this more deeply you will probably find that much (even most) of the "lagginess" is not the GC's fault. I suspect that it is mostly due to JIT compilation. Calling System.gc() could improve things, but I doubt that it will get rid of the lagginess entirely.
Related
I have to write a program that is thought to run 'forever' , meaning that it won't terminate regularly. Up until now I always wrote programs that would run and be terminated at the end of the day. The program has to do some synchronizations, pause for n minutes and than sync again.
AFAIK there should be no problem with my current implementation and it should theoretically run just fine, but I'm lacking any real-world experience.
So are there any 'patterns' or best practices for writing very robust and resource efficient java programs that have a very long runtime? What could be possible problems after for example a month/year of runtime?
Some background :
Java : 1.7 but compiled down to 1.5
OS : Windows (exact version is not certain yet)
Thanks in advance
Just a brain dump of all the things I've had to keep in mind when writing this kind of app.
Avoid Memory Leaks
I had an app that runs once at mid day, every day, and in that I had a FileWriter. I wasn't closing that properly, and then we started wondering why our virtual machine was going into melt down after a few weeks. Memory leaks can come in the form of anyhing really, with one of the most common examples being that you don't de-reference an object appropriately. For example, using a class's field as a method of temporary storage. Often the class persists, and so does the reference. This leaves you with objects, sitting in memory and doing nothing.
Use the right kind of Scheduler
I used a java Timer in that app, and later I learnt that it's better to use a ScheduledThreadPoolExecutor when another app was changing the System clock. So if you plan on keeping it completely Java based, I would strongly recommend using that over a Timer for all of the reasons detailed in this question.
Be mindful of memory usage and your environment
If your app is loading large amounts of data each and every day, and you have other apps running on the same server, you may want to be careful about the timing. For example, say at mid day, three of the apps run their scheduled operation, I would say running it at any other time would probably be a smart move. Be mindful of the environment in which you're executing your code in.
Error handling
You probably want to configure your app to let you know if something has gone wrong, without the app breaking down. If it's running at a certain time every few hours, that means people are probably depending on it, so I would have a function in your Java code that sends out an email to you, detailing the nature of the exception.
Make it configurable
Again, if it needs to run at various points in the day, you don't want to have to pull the thing down for a few hours to work out some minor changes to your code. Instead, port it into a java Properties file, or into an XML Config (or really, whatever). The advantage of this is that you can update your program and get it up and running before anyone really noticed the difference.
Be afraid of the static keyword
That bad boy will make objects persist, even when you destroy their parent reference. It is the mother of all memory leaks if you are not careful with it. It's fine for constants, and things that you know don't need to change and need to exist within the project to run well, but if you're using it for random values inside a project, you're going to quickly wonder why your app is crashing every few hours rather than syncing.
Props to #X86 for reminding me of that one.
Memory leaks are likely to be the biggest problem. Ensure that there are no long-term references held after an iteration of your logic. Even a relatively small object being referenced forever, will exhaust the memory eventually (and worse, it's going to be harder to detect during testing if the growth rate is 1GB/month). One approach that may help is using the snapshot functionality of profilers: take a snapshot during the pause, let the sync run a few times, and take another snapshot. Comparing these should show the delta between the synchronizations, which should hopefully be zero.
Cache maintenance is another issue. The overall size of a cache needs to be strictly limited (whereas often you can get away without in short-running programs, because everything seen will be small enough to not cause problems). Equally it's more important to do cache-invalidation properly - broadly speaking, everything that gets cached will become stale at some point while your program is still running, and you need to be able to detect this and take appropriate action. This can be tricky depending on where the golden source of the cached data is.
The last thing I'll mention is exception-handling. For short-running processes, it's often enough to simply let the process die when an exception is encountered, so the issue can be dealt with, and the app rerun. With a long-running process you'll likely need to be more defensive than this. Consider running parts of your program in threads, which can be restarted* if/when they fail. You may need a supervisor-type module, which checks that everything else is still heartbeating and reboots it if not. If appropriate to your structure, this is anecdotally a lot easier to achieve with actors-style libraries rather than Java's standard executors. And if it's at all possible, you may want to have hooks (perhaps exposed over JMX/MBeans) that let you modify the behaviour somewhat, to allow a short-term hack/workaround to be affected without having to bring the process down. Though this requires quite some amount of foresight to predict exactly what's going to go wrong in several months...
*or rather, the job can be restarted in another thread
I just installed the Unnecessary Code Detector for Eclipse and ran it on my project. I see a lot of so-called "dead code". Although, from an organizational standpoint, it makes sense to remove dead/unnecessary code, it got me thinking:
Does dead code actually hinder a Java app's performance?!?!
To me, if code is truly "dead", it never gets executed, so I don't see how removing it (again, except for organizational/housekeeping/code cleanup purposes) could ever improve performance.
I don't think "dead code" will hinder application performance, but it will hinder development performance, which is invariably more expensive.
Where possible the JIT compiler may remove this kind of dead-code - see dead-code elimination. I suppose in theory if the JIT compiler removed huge amounts of dead-code it could impact initial compilation.
However I doubt this would occur in practice, and I'd only recommend dead-code removal to make development easier/faster.
It could affect a few things...
Size of the application
Memory used when application is running
Decreased performance on package scanning (if applicable)
It could affect it a bit, but the JIT compiler should be able to detect and eliminate methods that are never used. And even if it doesn't, the overheads (memory, load time, JIT compilation time, etc) are likely to be small.
A much better reason to eliminate dead methods is to get rid of "old stuff" that makes your codebase harder to read, test, maintain. If this is code that you might conceivably need again, you can always get it back from version control.
What if I ask the user which method do you want to call? , take the input as a String and then invoke that method using reflection?. The JIT can't say which method will be used so it can't remove any methods :).
Good point. So it probably won't eliminate methods in practice. (But it could ... if the classloader knew where to reload the method from ...)
Dead methods increases method area in JVM.
Yes, though the percentage memory increase is probably insignificant. And the consequent performance reduction is probably even less significant.
Also a method that is never called will never be JIT compiled, so you are likely to not incure 50% or more of memory usage for a typical live method.
So too much dead code miight lead to unloading of classes from the method area (heap) which could affect app performance. am I right?.
That is highly unlikely. A class will only be unloaded if nothing references it and its classloader is also unreachable. And if it does happen, the class would not be used again anyway, so it is right to unload it.
It could affect performance of your application.
Edit
One way to look at it is; dead code is going to add some extra memory to your running application. So it will impact application performance as well.
I wrote a simple code in Java that uses the Robot class to move the mouse according to some conditions.
Although the code works nicely, there seems to be a 'lag' when other applications are running.
I think Java has some issues posting system messages.
Is there a workaround to avoid this?
Before you start thinking about reducing the lag, you must first understand it's causes. I'll present the answer(s) in a fashion in which you can understand the "why" along with the "what to do".
By your description that the lag only occurs when other programs are running along with your robot, the most likely causes for the lag are:
Lack of system resources - Too many things running at the same time, consuming too much memory/processing-power, thus making the OS slow-down some programs in order to be able to run the others.
What to do: To try to fix such issues, you can try to optimize your code, to make it use less memory/processing power, thus reducing the cause of the lag, with implicitly reduces the lag itself. Unfortunetly tough, it's hard to legally do the same for any 3rd party programs, so the lag can hardly be completely removed if the concurrent applications are not yours.
Concurrency regarding a non-replicable, non-shareable component - One or more components that cannot be accessed by more than one process at a time and that cannot be cloned into multiple instances needs to be used by more than one process that is running. While one process takes control of it, any other processes have no choice but wait for the component to be freed.
What to do: In this case, there hardly is any legal method other than to reduce the concurrent process's priority while increasing your's (effectively slowing them down in order for your program to run faster), or shut them down completely.
How to do: To increase your process's priority, this is the code to set it at 80% (default is usually 50%), inset at your main():
Thread.currentThread().setPriority((int)(Thread.MAX_PRIORITY*0.8));
Note: You can set your process to "never" let go of whatever components it needs, using Thread.MAX_PRIORITY without multiplying by 0.8, but that is unrecommended, as it will pretty much pause any process that requires the components (quasi-same to shutting them down while yours is running), and if your program hangs, for whatever reason, so will those, as the components are never released.
I have a multi-threaded application which scales well to begin with, but running on a 16-cpu server, once I exceed 5 or 6 hardware threads the performance levels off. I suspect that the bottleneck surrounds one of the synchronized methods. However, I need to be sure it's the guilty method before I start diving into the code and trying to replace the algorithm with a non-blocking one.
Running Java with the -Xprof argument tells me that, as I expected, the threads are spending most of their time blocked. Is there a way that I can break that down into how much time they spend blocked at a particular method?
http://yourkit.com the monitor view will tell you which lock classes are hot, who is holding the contended locks and breakdown by lock instance and caller stack. There is 30 day evaluation period of the tool.
The jvisualvm tool that comes with the JDK can help you a little bit, although its CPU profiling information is rather limited (more of a visualizer for Xprof data). I generally find it more useful for memory profiling.
JProfiler has a pretty nice CPU profiler with some really cool functionality that might help you, but it's commercial.
Or, you could add statistics gathering to your code (e.g., measuring how much time it takes to execute each synchronized method you suspect, breaking it into time waiting for sync / time executing the method), although that's a lot more work.
Could you try this method? If it works across multiple CPUs it should find the problem, but that's a big "if".
Basically, when you see that a thread is blocked, the call stack tells you exactly why. If you're not sure if you're seeing the real problem, do it a few times.
Eclipse TPTP is another very good and free profiler.
I have been writing a small java application (my first!), that does only a few things at the moment. Currently, it runs the Main class which launches a gui class (a class I wrote that extends JFrame that only contains a JTextArea), a class that loads a local file through a BufferedInputStream that is approximately 40kb, and class that loads a entry from a Java properties file.
Everything works wonderfully, however, I was watching the Windows task manager and I noticed something that struck me as odd. When I launch the application, the RAM usage jumps to about 40MB while it loads the local file and pulls a few values from it to display in the JTextArea, which seems normal to me because of the JVM, Java base classes, etc. At this point, however, when the application has finished loading the file, itmerely sits idle, as I currently don't have it doing anything else. While it is sitting idle, as long as the window is active, the application's memory usage starts climbing by 10-20kb every second. This strikes me as odd. If I click on another program to make this one the inactive window, the memory still rises, but at a much slower rate (about 10kb every 3-5 seconds).
I have not tested to see how far it would go up, but this strikes me as very odd behavior. Is this normal Java behavior? I guess it is possible that my code could be leaking memory, but I'm not sure how. I did make sure to close the BufferedInputStream I am using, and I can't see what else would cause this.
I'm sorry if my explanation doesn't make sense, but I would appreciate any insight and/or pointers anyone may have.
UPDATE:
Upon suggestion, I basically stripped my application down to the Main class which simply calls the gui class. The gui class only extends JFrame and sets the window size, close operation, and visible properties. With these changes, the memory still grows at 10-20kb, but at a slower rate. This, in conjuction with other advice I have received leads me to believe that this is just Java. I will continue to play with it and let you all know if I find out anything else interesting.
Try monitoring the heap usage with jconsole instead of the Windows task manager:
Launch your app with the -Dcom.sun.management.jmxremote option e.g.
java -Dcom.sun.management.jmxremote -jar myapp.jar
Launch jconsole from the command line, and connect to the local pid of the java process you started in the last step.
Click over to memory and watch heap memory (the default display)
If you watch for a while, you'll probably get a "sawtooth" pattern as the memory climbs over time, but then has sharp drop-offs when the garbage collector runs. You can try to "suggest" garbage collection by clicking the so-labelled button.
When you do this, does the memory usage drop down to the same minimum level, or is the overall minimum increasing over the course of several minutes? If the minimum usage increases, then you have a memory leak. If it always returns to the same minimum level, then you're fine.
Congrats on your first app! Now, a couple things to think about. First, the Windows task manager is not a great resource to understand how quickly your vm is growing. Instead, you should monitor your garbage collection stats in the console (use the -verbose:gc commandline param). Second, if you are concerned about potential leaks and the growth of the vm, there are a bunch of great profilers out there that are easy to use and can help you diagnose memory issues. check out these two posts for some profiler options.
Congratulations for your first Java app!
Java applications run in a virtual machine. The virtual machine has been assigned a fixed amount of memory by the OS, typically 512 MB. As long as the application uses less than 512 MB the garbage collector won't kick in and start searching for "dead" memory blocks. The JVM memory limit can be modified in most OSes. Try switching the memory limit to 32 MB, for example.
Is this normal Java behavior?
No.
I guess it is possible that my code could be leaking memory
That is definitely the cause. Please post your source code, otherwise further diagnosis isn't possible.
I noticed you are using Swing, make sure you are launching your JFrame in the event dispatch thread, using the invokeLater(Runnable) method.
If your are using any sort of collections, make sure you clear them once done.
Since you are doing some file IO, make sure you close all of the classes involved in in the IO operations after you are done with them.
If you are using any event listeners, remember to explicitly remove event listeners when they are no longer necessary.
One thing you could try is experimenting. Take your application and remove the file IO, see what happens. Does the memory usage still climb as before? Now resotre your application to normal, and remove the text area - does the memory still climb as before? Etc, etc. This will help you to determine what the source is, and you can focus your efforts there. Most likely you will uncover what you are after by doing this.
Another useful diagnosis tool is to use System.gc() at particular points in time, usually after the heavy-lifting blocks of code. This will tell the JVM to perform a garbage collection at that point in the execution, rather than at another time determined by memory consumption. This will help you to take into account any periodic fluctuations in the memory usage of your application.
Failing which, you can always use a memory profiler. If you are using Netbeans IDE, there's one built right into it. For Eclipse, there're several plugins which can perform profiling.
it is normal. some background calc might leave dead objects around, which JVM isn't in a hurry to clean up. eventually they will be garbage collected, when max mem is approached.
leave your program running overnight, and your machine won't blow up.