|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 6
Except for such special cases, you're best off avoiding the usage of the wrapper classes and staying with the base types. This avoids both the memory and performance overhead of object creation.
Besides the actual wrapper types, other classes in the class libraries take values of primitive types and add a layer of semantics
and behavior. Classes such as java.util.Date and java.awt.Point are examples of this type. If you're working with a large number of values of such types, you can avoid excessive object
overhead by storing and passing values of the underlying primitive types, only converting the values into the full objects
when necessary for use with methods in the class libraries. For instance, with the Point class you can access the internal int values directly, even combining them into a long so that a single value can be returned from a method call. The following code fragment illustrates this approach with a simple
midpoint calculation:
...
// Method working with long values representing Points,
// each long contains an x position in the high bits, a y position
// in the low bits.
public long midpoint(long a, long b) {
// Compute the average value in each axis.
int x = (int) (((a >> 32) + (b >> 32)) / 2);
int y = ((int) a + (int) b) / 2;
// Return combined value for midpoint of arguments.
return (x << 32) + y;
}
...
Now let's consider another approach to reducing object churn: reusing objects. There are at least two major variations of this approach, depending on whether you dedicate the reused object for a particular use or use it for different purposes at different times. The first technique -- dedicated object reuse -- has the advantages of simplicity and speed, while the second -- the free pool approach -- allows more efficient use of the objects.
The simplest case of object reuse occurs when one or more helper objects are required for handling a frequently repeated task.
We'll use date formatting as an example, since it's a function that occurs fairly often in a variety of applications. To just
generate a default string representation of a passed date value (represented as a long, let's say, given the preceding discussion of using primitive types), we can do the following:
...
// Get the default string for time.
long time = ...;
String display = DateFormat.getDateInstance().format(new Date(time));
...
This is a simple statement that masks a lot of complexity and object creation behind the scenes. The call to DateFormat.getDateInstance() creates a new instance of SimpleDateFormat, which in turn creates a number of associated objects; the call to format then creates new StringBuffer and FieldPosition objects. The total memory allocation resulting from this one statement actually came out to about 2,400 bytes, when measured
with JRE 1.2.2 on Windows 98.
Since the program only uses these objects (except the output string) during the execution of this statement, there's going to be a lot of object churning if this use and discard approach is implemented in frequently executed code. Dedicated object reuse offers a simple technique for eliminating this type of churn.