3

Which is better for memory management, or any other reason, or are these two scenarios the same:

Calendar currentDateTime = Calendar.getInstance();
int i= foo.getSomething(currentDateTime);
Bar bar= foo.getBar(currentDateTime);

The other code block:

int i= foo.getSomething(Calendar.getInstance());
Bar bar= foo.getBar(Calendar.getInstance());

The general question is, is it better to get an instance of an object, then use that instance when needed, or make the getInstance() call each time when needed. And, does the answer change if not dealing with a singleton, but making a plain POJO?

8 Answers 8

7

To be clear, Calendar is not actually a singleton. Calendar.getInstance() returns a new object each time you call it.

This means that the answer to your question depends on whether or not the functions getSomething() and getBar() have side effects that cause foo to store the new Calendar instance. In general, good programming practices dictate that this won't be the case.

EDIT: However, each time you call Calendar.getInstance() you could end up with a different date. This may be an important detail depending on what your functions are doing.

EDIT 2: it also depends on how often you do the above process. As another answer pointed out, instantiating Calendar objects can be intensive. If you only do it twice, then it doesn't matter if you cache it. If you do this very often, then you may consider changing your approach or doing some caching.

Sign up to request clarification or add additional context in comments.

Comments

2

Calendar is a very expensive object (one of the most expensive date objects in any library I know of). Calling getInstance() is very expensive too. If you have to use Calendar you could look at caching it. It really depends on why you need it.

The most efficient way to obtain and store the current time is using a long primitive.

long currentDateTime = System.currentTimeMillis();

If you use GMT time internally, you can store the current day with

int currentDay = (int)(System.currentTimeMillis() / 86400000);

EDIT: It is worth testing on your machine, while getInstance() is relatively expensive but it is still fairly fast. On my old box it takes ~20 micro-seconds. On a fast machine currentTimeMillis() can take 140 nano-seconds.

The following prints

Calendar.getInstance() took on average 20088 ns. java.util.GregorianCalendar[time=1294086899359 ... deleted ...]
System.currentTimeMillis() took on average 938 ns. 1294086899377

code

int runs = 10000;
long start = System.nanoTime();
Calendar cal = null;
for(int i=0;i<runs;i++)
    cal = Calendar.getInstance();
long time = System.nanoTime() - start;
System.out.println("Calendar.getInstance() took on average "+time/runs+" ns. "+cal);

long start2 = System.nanoTime();
long now = 0;
for(int i=0;i<runs;i++)
    now = System.currentTimeMillis();
long time2 = System.nanoTime() - start2;
System.out.println("System.currentTimeMillis() took on average "+time2/runs+" ns. "+now);

3 Comments

What would make Calendar so expensive?
It contains, a timezone, locale, an int[] for its day/month/year/hours/minutes/seconds and a boolean array which says which of these values have been set. It has a "Pseudo-time-stamps which specify when each field was set." which is an int[] and a field for the min value. It has the time in mill-seconds cached, a boolean to say if any fields are set, another to say if all fields are set, another to record whether lenient is true, an int to record which is the first day of the week, another for minimalDaysInFirstWeek, a serialVersionOnStream for decoding old serialized versions....
.. a long field for Gregorian cut over date, and another for the day, the cutover year, when the Julian dates ended. Three references to how Gregorian and Julian dates are calculated, an int[] for time zone offsets, an int[] for the original values of the fields... That could be it, but its hard to tell. ;)
0

For a singleton, it doesn't make much of a difference. By using a temporary variable, you are saving the overhead of a function call, but nothing more - the same object is being returned each time.

If you are making a POJO, either by calling a constructor or by using an object-creation static method, you are creating a new object. This means that you have the run-time overhead of a function call, as well as the memory overhead of another object being created.

In general, if I am planning on using the same object several times within a method body, I will use a temporary variable. This way, I am doing the same thing whether I need to avoid memory overhead or not, and my code will be more consistent for it.

1 Comment

FWIW, Calendar is not a singleton. I'm not certain that's what you or OP were implying, but I just thought I'd bring it up considering they mentioned both Calendar and getInstance together in the same question.
0
  1. uses more memory and less CPU
  2. uses less memory and more CPU

You have to decide what you want to give for the operation. What is the bottleneck in your application.

5 Comments

You should probably add why this is. Reason being in 1. we are allocating memory to currentDateTime to store value for use later whereas in 2. we Calendar.getInstance() twice accounting for the more CPU less memory.
Either could consume more memory depending on how it is called and how often. Calling getInstance() repeatedly will create far more garbage to clean up.
my guess was that 1. uses less memory, because "currentDateTime" is passed by reference to the methods, is that thinking wrong, what am i missing?
Your 2nd case is not entirely right. With thow Calendar.getInstance() calls, the Calendar object are created twice, so it's using more memory and more CPU.
You can't say that for certain. The optimizer is free to do whatever it wants.
0

You are basically looking at two different scenarios: 1. Calendar is a singleton, in which case you will have to call a helper method to get the single instance that is in memory. 2. Calendar is a POJO. If getInstance() simply calls the constructor, then you will be creating a new instance every time you invoke it. As such, you may be getting different unexpected results in your latter case.

The bottom-line, though, is that it comes down to coding-style and readability. Some developers prefer using factory methods, some prefer simply calling the constructor directly. In my mind, if the object is a simple entity (i.e. no build-up required), then calling new is the most straight-forward method of creating an object. If, on the other hand, there is some build-up involved, and you want generally more readable code, then a factory method is much more preferred.

From a memory-management perspective, every time you call the constructor, you will get a new instance of the class. Are you going to use that new instance? Do you have references to that new instance that might keep it from being garbage collected in a timely manner? Those questions are a bit more meta.

Comments

0

If you are only interested in reading from the calendar instance the first method is marginally better, since the garbage collector won't have quite so much work to do, and you will only be storing/making a heavyweight object once.

Comments

0

The first block queries the current date and time once. This is good, since you probably want to use the same timestamp for both.

The second example is slower since it has to initialize a new Calendar object. Also there may be two different timestamps. Ask yourself what will happen around midnight when the first method is called with a time of 23:59:59.875 and the second method is called with a time of 00:00:00.007. Do you really want that?

Technically and strictly the first code snippet claims some memory for a longer time. But in pretty much all cases you should be fine with that and go with the second code snippet.

And by the way: You can assume that local variables don't cost any memory. Especially in often-used code they will be optimized away.

Comments

0
  1. uses less memory and less CPU
  2. uses more memory and more CPU

The garbage collector is free to collect the Calendar instance immediately after the last use of a reference to it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.