One day or the other every java developer will come across the out of memory error. If you are lucky enough you will notice that in your dev boxes, otherwise you will get the attention by your management within overnight causing the application to crash.

OutOfMemory in Heap:

In the heap we get an OutOfMemoryError, if the garbage collector cannot reclaim enough memory for a new object. In such situation the Sun HotSpot JVM shows this error message:Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space

The first error is thrown if there are too many threads in the JVM and there is not enough memory left to create a new thread. This is because the memory limits of a process have been reached or the maximum number of file handles for the user that executes the java process has been reached. The second error message indicates that a memory allocation error on a native stack (JNI method call) has occured.

It is also interesting that a memory allocation error on the JVM stack (too many frames on the stack) does not throw an Java OutOfMemory error but as the JVM specification mandates: java.lang.StackOverflowError.

This error is thrown if there is not enough memory left on the operating system level – which is normally true if other processes are using all of the available memory or the swap space is configured too small.

I have always enjoyed debugging rather than coding. This post is about some of the troubleshooting methods that I came across while debugging.

Debugging is locating the defects. In the book Debugging, David Agans formulates nine rules of debugging for successful search of a bug.

Understand the system.

Make it fail.

Quit thinking and look.

Divide and Conquer.

Change one thing at a time.

Keep an audit trail.

Check the plug.

Get a fresh view.

If you don’t fix it , it ain’t fixed.

You cannot locate the defects unless you are familiar with the system. Though it takes most of your time, it is worth doing it. You need the understanding of the finer details.

Reduce the problem to its essence. Determine the smallest input that will cause the bug. The simpler the data or path to the bug, the more easily you can deduce or track down the problem.

You must change the conditions of the test to see if your bug disappears. If you correct the bug with a change, that change might tell you what the problem is, or at least give you a big hint about what is going on. You form hypotheses with your logic and deductive reasoning skills and then filter them by experimentation and observation. For example, by experimentation, we concluded that the specific argument caused the problem. Finally, we narrowed it down (by using some experience) to the equals as escape problem.

Experience helps in the debugging process in two ways: first, you hone your ability to execute the previous four elements; and second, you might have seen a similar bug or just plain know more about a particular problem.

When it comes to testing and debugging, a model-view-controller architecture has several benefits. For testing, one can build and add new controllers that invoke services of the model—for instance, controllers that automate execution of these services. For debugging, one can register special views that automatically log all changes to the model. Finally,every observer and model can be examined and tested in isolation, thus reducing complexity.

Debugging sessions:

Java bytecode – using system.out.println. Java Pitfalls by Michael C. Daconta shares a useful technique for applying the println() method. Daconta suggests creating a DebugManager() class that allows you to set a debug flag based on certain classes or applications.

Using comments – comment out larger part of code and narrow down the search.

Remote debugging -running an application on one computer and debugging it on another computer.

Debugging on demand -you open a debugging session whenever an unhandled exception or other unrecoverable error occurs in your program.

Compilation or syntactical errors are the first that you will encounter and the easiest to debug. They are usually the result of typing errors.

Logic errors are different from run-time errors because there are no exceptions thrown, but the output still does not appear as it should. These errors can range from buffer overflows to memory leaks.

Run-time errors occur during the execution of the program and typically generate Java exceptions.

If you use the javac compiler to build your code for debugging, use the -g compiler option. You can still set breakpoints and step through your code if you do not compile your classes with the -g option; however, you will not be able to inspect variables. The -g option lets you include debugging information in compiled code. This is useful if you want to be able to run the java debugger (jdb).

Keep in mind that if you compile with the -O option that optimizes your code, you will not be able to debug your classes. Optimization will remove all debugging information from the class.

You can manually force the generation of a stack trace using either the following statements.

* Throwable().printStackTrace() to generate a trace of the method’s code at a single point in time. The trace will show the method’s calls across threads.

* Thread.currentThread.dumpStack() to generate a snapshot of the current thread only.

Diagnostic methods:

The Java language provides methods from the Runtime() class to trace the calls you make to the Java virtual machine.

Turn on tracing will produce a list of every method call your program makes:

traceMethodCalls(true)

Turn off tracing by adding the following line to your source code:

traceMethodCalls(false)

Of the all, log files are the best sources of debugging. If you practice debugging through logs, its of much useful in troubleshooting production issues where you are provided with none other than logs. Logging statements serve no other purpose than debugging,they do not help us in understanding the code.The main message a logging statement conveys is that the procedure in question was in need of debugging. Therefore, logging is to be done with specific code locations, events and data. For performance reasons,output is typically buffered before actually being written to the output device. In the event of a program crash,this buffered output is lost. Using ordinary (buffered) output for logging thus hides what happened in the last few events before the crash. One can either use an unbuffered channel for logging (introducing a slowdown,as described previously) or make sure that the program flushes its buffered logs in case of a crash.

When redirecting output from an application using the “>” symbol, error messages still print to the screen. This is because error messages are often sent to the Standard Error stream instead of the Standard Out stream. To redirect STDERR specify “2>” by which the error messages are redirected to the specified channel

One of the common problems that most developers tend to face at some point is defensively over checking for nulls. Many anticipate the null response without trusting the contract and bloat the code with !=null conditions making it unreadable and ugly. Often times a method needs to return a value or nothing depending on its internal and working state. Here nothing includes the null value too which means returning a null value is a valid one by contract.

To be precise, we have two options in getting the response

i. null is not allowed

ii. null is allowed

option i is easy to handle. If null is not allowed,

Use assert and throw an error stating it. The JRE is configured by default to ignore the asserts. By using the option -esa (enablesystemassertions), one can enable asserts to various levels like classes or packages.

option ii – null is allowed and if it is passed from external method, then one have to be careful in dealing with it. You have no choice other than using

if( value !=null)

doSomething()

else

doOtherthing();

Its one time checking. You are sure that value cannot be null for the rest of the program and you are free to use the variable in subsequent methods without any block to check for null conditions.

On the other way, if you have control over the external method, then you can force the method to return empty string or empty collections instead of null as described in NULL OBJECT pattern.

The Null Object says, “Just because I don’t have anything and don’t do anything, it does not mean that I am not smart. By not having anything, I don’t take up much resource and can be shared among many. By not doing anything, I am doing the right thing.”

Martin Fowler claims Nulls are awkward things and comes up with this particular refactoring pattern.

“Abstraction and encapsulation are complementary concepts: abstraction focuses on the observable behavior of an object… encapsulation focuses upon the implementation that gives rise to this behavior… encapsulation is most often achieved through information hiding, which is the process of hiding all of the secrets of object that do not contribute to its essential characteristics.”

Encapsulation is wrapping data and functions that operate on that data inside an object where as information hiding is hiding internal details of the object.

The area is calculated by side * side and it is specific to the Class Square. Hence the implementation of getArea should be within the class Square which is Encapsulation and the method of how to calculate the area of the square should not be exposed to the external class which is Information Hiding.

Wrapping of data and functions doesn’t mean that creating public properties for each field and all fields are to be made private. The getter and setter methods are to be selected carefully. Expose only the properties that will be accessed by others.

Neal Ford in ‘The productive Programmer’ explains how to choose the properties in ‘Breaking Encapsulation’.

1. Create properties only when you need them. It avoids the unnecessary coding and code bloating. Also you don’t have to unit test that property since it is always called from other code.

2.Create atomic mutator instead of creating public properties for each field.

It would print 2 and 3. The problem is, because Calendar is not aware of its state and its ability to set individual properties separately. It cannot be made atomic since it keeps track of time too. Since Calendar has too many responsibilities its behavior is uncertain.

“Instead of blindly creating properties when you create a new class, here is an alternative strategy: create properties only when you need to call them from other code. This serves several
purposes. First, you don’t have any code you don’t actually need. Developers create far too much speculative code because they think “I’m sure I’ll need that later, might as well create it
now.” Because you are letting the tool create properties for you anyway, it’s no more work to create them as you need them than to create them up front. Second, you cut down on needless
code bloat. Properties take up lots of space in source files, and reading through all that boilerplate code slows you down. Third, you don’t have to worry about writing unit tests for
your properties. Because you are always calling them from some other method that utilizes the property, they will automatically get code coverage in your tests. I never do test-driven
development for properties (get/set methods in Java, properties in C#); instead, I allow them to come into being only when there is a real need.”

Sriram ensures that Encapsulating an object is not about protecting (or securing) the said object. If you must think in terms of protection, then it is about protecting the consumers (callers) of the object. Encapsulation is about freeing your consumers from the knowledge of your implementation details. By doing so, you insulate your consumers from any ripple effect of changes to your implementation.