In Java, Is It More Efficient to Use Byte or Short Instead of Int and Float Instead of Double

In java, is it more efficient to use byte or short instead of int and float instead of double?

Am I wrong in assuming it should be faster and more efficient? I'd hate to go through and change everything in a massive program to find out I wasted my time.

Short answer

Yes, you are wrong. In most cases, it makes little difference in terms of space used.

It is not worth trying to optimize this ... unless you have clear evidence that optimization is needed. And if you do need to optimize memory usage of object fields in particular, you will probably need to take other (more effective) measures.

Longer answer

The Java Virtual Machine models stacks and object fields using offsets that are (in effect) multiples of a 32 bit primitive cell size. So when you declare a local variable or object field as (say) a byte, the variable / field will be stored in a 32 bit cell, just like an int.

There are two exceptions to this:

  • long and double values require 2 primitive 32-bit cells
  • arrays of primitive types are represent in packed form, so that (for example) an array of bytes hold 4 bytes per 32bit word.

So it might be worth optimizing use of long and double ... and large arrays of primitives. But in general no.

In theory, a JIT might be able to optimize this, but in practice I've never heard of a JIT that does. One impediment is that the JIT typically cannot run until after there instances of the class being compiled have been created. If the JIT optimized the memory layout, you could have two (or more) "flavors" of object of the same class ... and that would present huge difficulties.



Revisitation

Looking at the benchmark results in @meriton's answer, it appears that using short and byte instead of int incurs a performance penalty for multiplication. Indeed, if you consider the operations in isolation, the penalty is significant. (You shouldn't consider them in isolation ... but that's another topic.)

I think the explanation is that JIT is probably doing the multiplications using 32bit multiply instructions in each case. But in the byte and short case, it executes extra instructions to convert the intermediate 32 bit value to a byte or short in each loop iteration. (In theory, that conversion could be done once at the end of the loop ... but I doubt that the optimizer would be able to figure that out.)

Anyway, this does point to another problem with switching to short and byte as an optimization. It could make performance worse ... in an algorithm that is arithmetic and compute intensive.



Secondary questions

I know java doesn't have unsigned types but is there anything extra I could do if I knew the number would be positive only?

No. Not in terms of performance anyway. (There are some methods in Integer, Long, etc for dealing with int, long, etc as unsigned. But these don't give any performance advantage. That is not their purpose.)

(I'd assume the garbage collector only deals with Objects and not primitive but still deletes all the primitives in abandoned objects right? )

Correct. A field of an object is part of the object. It goes away when the object is garbage collected. Likewise the cells of an array go away when the array is collected. When the field or cell type is a primitive type, then the value is stored in the field / cell ... which is part of the object / array ... and that has been deleted.

Why does the Java API use int instead of short or byte?

Some of the reasons have already been pointed out. For example, the fact that "...(Almost) All operations on byte, short will promote these primitives to int". However, the obvious next question would be: WHY are these types promoted to int?

So to go one level deeper: The answer may simply be related to the Java Virtual Machine Instruction Set. As summarized in the Table in the Java Virtual Machine Specification, all integral arithmetic operations, like adding, dividing and others, are only available for the type int and the type long, and not for the smaller types.

(An aside: The smaller types (byte and short) are basically only intended for arrays. An array like new byte[1000] will take 1000 bytes, and an array like new int[1000] will take 4000 bytes)

Now, of course, one could say that "...the obvious next question would be: WHY are these instructions only offered for int (and long)?".

One reason is mentioned in the JVM Spec mentioned above:

If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte

Additionally, the Java Virtual Machine can be considered as an abstraction of a real processor. And introducing dedicated Arithmetic Logic Unit for smaller types would not be worth the effort: It would need additional transistors, but it still could only execute one addition in one clock cycle. The dominant architecture when the JVM was designed was 32bits, just right for a 32bit int. (The operations that involve a 64bit long value are implemented as a special case).

(Note: The last paragraph is a bit oversimplified, considering possible vectorization etc., but should give the basic idea without diving too deep into processor design topics)


EDIT: A short addendum, focussing on the example from the question, but in an more general sense: One could also ask whether it would not be beneficial to store fields using the smaller types. For example, one might think that memory could be saved by storing Calendar.DAY_OF_WEEK as a byte. But here, the Java Class File Format comes into play: All the Fields in a Class File occupy at least one "slot", which has the size of one int (32 bits). (The "wide" fields, double and long, occupy two slots). So explicitly declaring a field as short or byte would not save any memory either.

In Java does anyone use short or byte?

They are used when programming for embedded devices that are short on memory or disk space. Such as appliances and other electronic devices.

Byte is also used in low level web programming, where you send requests to web servers using headers, etc.

Processor usage when using byte and short data types in Java

In order to do computation (like x+y), processor need to load both x and y in registers (depends on architecture, but at least on of x or y should be in registers). Registers have size of 32 or 64 bits (at least on platforms where Java can be used). So, this values are anyways are converted to 32(64) bit integer. It is done automatically and does not consume additional CPU resources. So computational speed will be the same.

In what situations is it better to use a float over a double in Java?

Since your question is mostly about performance, this article presents you with some specific calculations (keep in mind though that this article is specific to neural networks, and your calculations may be completely different to what they're doing in the article): http://web.archive.org/web/20150310213841/http://www.heatonresearch.com/content/choosing-between-java%E2%80%99s-float-and-double

Some of the relevant material from the link is reproduced here:

Both double and float can support relatively large numbers. The upper
and lower range are really not a consideration for neural networks.
Float can handle numbers between 1.40129846432481707e-45 to
3.40282346638528860e+38...Basically, float can handle about 7 decimal places. A double can handle about 16 decimal places.

Matrix multiplication is one of the most common mathematical
operations for neural network programming. By no means is it the only
operation, but it will provide a good benchmark. The following program
will be used to benchmark a double.

Skipping all the code, the table on the website shows that for a 100x100 matrix multiplication, they have a gain in performance of around 10% if they use doubles. For a 500x100 matrix multiplication, the performance loss because of using doubles is around 7%. And for a 1000x1000 matrix multiplication, that loss is around 17%.

For the small 100x100 matrix switching to float may actually decrease
performance. As the size of the matrix increases, the percent gain
increases. With a very large matrix the performance gain increases to
17%. 17% is worth considering.

Java 64bits - Integer vs Short

tl;dr

Unless you have a very special use-case, just use:

  • Integer for business object values, member variables on a class.
  • int for large amounts of raw data.

Just use Integer

For most common business-oriented Java apps, common practice is to just use the 32-bit int or Integer without much further thought, unless you know you will have values over 2 billion in which case use long or Long. On modern conventional hardware, there is little reason to fret over using short/Short.

Special cases

But since you asked “is there anything else to take into consideration at time to chose”, here are three special cases: enforcing limits, porting C code, and alternative hardware.

Enforce limit

If you want to enforce the limits of a short or Short, use those types. Choose these when you know you should have only values less than approximately 32,000, and want the compiler or runtime JVM to enforce that.

For example, add one to 101:

short oneOhOnePlusOne = ( (short) 101 + (short) 1 ) ;
System.out.println( "oneOhOnePlusOne: " + oneOhOnePlusOne ) ;

102

Next, try to exceed the limit to see the compiler enforce the limit.

short shortMaxPlusOne = ( Short.MAX_VALUE + (short) 1 ) ;
System.out.println( "shortMaxPlusOne: " + shortMaxPlusOne ) ;

error: incompatible types: possible lossy conversion from int to short

See this code run live at IdeOne.com.

Porting C code

These various numeric types were likely put in Java to make easier to port C code, easier both both practically and psychologically. The inventors of Java were well aware that during that era most every attempt at a new programming language failed with the criticism that it was “not like C”. Thus Objective-C (an inspiration for Java), and thus the monstrosity that is C++.

So, indeed, if you are porting C code, use the matching type to replicate behavior.

By the way… Technically, C does not actually define the size of its numeric types. In practice virtually every implementation of C uses the sizes as seen in Java.

FYI, even the most modern languages such as Swift and Kotlin have built-in numeric types for 8, 16, 32, and 64 bit integers.

More restrictive hardware

If there is any chance your app might run on other hardware not based on x86-64, then you may want to use these types. Alternate implementations of Java for such hardware might optimize better for the smaller types.

Primitive versus Object

Array of primitives are preferable for saving memory allocated

First of all, don't stress out on this. Don't fall into the trap of premature optimization. On conventional hardware with most common apps, any savings of memory on using primitives versus objects and arrays versus collections will be insignificant. Use the type (primitive/object) and structure (array/collection) appropriate to your coding context.

My practice:

  • In my code, objects.
    Use only objects (Integer, not int) within my own classes. I have two reasons. Firstly, I am among the camp of Object fans that wish Java were pure OOP without any primitives. (Indeed, there is research ongoing to see if primitives can virtually disappear in far-future versions of Java.) Secondly, I find when I used a primitive, I end up needing to use it in a context demanding objects, such as with collections.
  • With others’ code, use primitives if they do.
    Outside my own classes, I do not force the issue, as undue auto-boxing is senseless. If external code (not my own) is using primitives, I use primitives in that context.

Does using small datatypes reduce memory usage (From memory allocation not efficiency)?

C/C++ uses only the specified amount of memory but aligns the data (by default) to an address that is a multiple of some value, typically 4 bytes for 32 bit applications or 8 bytes for 64 bit.

So for example if the data is aligned on a 4 or 8 byte boundary then a "char" uses only one byte. An array of 5 chars will use 5 bytes. But the data item that is allocated after the 5 byte char array is placed at an address that skips 3 bytes to keep it correctly aligned.

This is for performance on most processors. There are usually pragmas like "pack" and "align" that can be used to change the alignment or disable it.

Transmitting primitive data such as an int,float-tuple: More efficient to parse strings or convert to byte array?

This is a rather complicated question.

  • On the one hand, it is (relatively) computationally expensive to convert a number from binary to text form ... and back. Converting to decimal is particularly expensive because the conversions involve repeated division / multiplication by 10.

  • On the other hand, if the data values are (on average) small, a textual representation may (on average) occupy fewer bytes when encoded. Depending on end-to-end speed and latency of your networks (including NICs, virtualization, etc) a smaller on-the-wire representation may result in greater throughput.

  • On the third hand, this would be moot if the communication costs were an insignificant part of the overall computation.

My advice would be:

  1. Beware of premature optimization!
  2. Benchmark the two alternatives (binary and text) for encoding + transmission + decoding in your environment. Make sure that you do this with test data that will be typical of your actual data.
  3. Benchmark the application as a whole. (This assumes that you paid attention to the first point!)
  4. Decide if the differences in binary versus text representation would make a significant difference to overall performance of the complete application on real data.
  5. Rework the code ... if your measurements, etc tell you it will be worth the effort.

Note: if measurement tells you that the difference between binary versus text is actually significant for your application, that could be a sign that your computation is spending too much time doing communication versus computation. It would be worth looking to see if you could reduce the amount of communication; e.g. by changing the granularity of the computation, or the amount of data that is being moved around.


Finally ...

When doing a lot of MapReduce operations, I'd like the data that is transmitted to have as little overhead as possible.

This should not be your goal. The goal should really be:

  • Make the application as a whole go fast enough to meet performance requirements.
  • Optimize developer time by not trying to achieve performance in excess of the actual requirements.

Goals like "as fast as possible" or "as efficiently as possible" or "as small as possible" can be dangerous effort sinks. You should try to avoid them.



Related Topics



Leave a reply



Submit