When writing something that creates many (1000s) of small objects often, should you try to minimize it for performance? Especially if you don’t know what system it will be run on, from low to high end desktops or even mobile. For mobile, I heard that creating a lot of objects hinders the performance a good bit, though I don’t know how true that is.
I have an example that shows this idea well. In a graphics program, say there is a method that is used for all drawing ideally called
drawPixel(Point). There could be 1000s of Points created and it may be repeated often, like in a game where it could be called 60+ times a second. Alternatively,
drawPixel(int x, int y) could be used to minimize the creation of many Point objects.
In an object-oriented design, I think using Point would be preferred. However, using primitive types may increase performance. The performance gain may be negligible in most cases, but I’m unsure about things like mobile or older machines. What is the performance gain from doing something like this and is it something that should be taken into consideration?
In general, no, you shouldn’t avoid creating objects for fear of performance loss. There are several reasons for this.
- Using objects is kind of the point of using Java. Avoiding them preemptively is a sign that the decision to use Java might not have been the right one to begin with.
- Performance issues are notoriously hard to predict. Never assume that something is a bottleneck. Always measure. Performance engineering is almost always a matter of making small changes in exactly the right place. You cannot predict the right place without measuring any more than you can predict a medication’s effect without an experiment.
- The cost of object creation is greatly overestimated. In a modern JVM it amounts basically to incrementing a pointer (and with generational garbage collectors, the cost of managing it is also trivial). There are a lot of texts on the internet that advise you to avoid objects, to use object pooling etc. This advise was sometimes right in the 1990s; today it is mostly obsolete. You are very unlikely to gain enough performance to justify the added development cost and complexity introduced by avoiding Objects or managing them yourself.
That said, there are places where making something into an object doesn’t make sense to begin with. Passing two coordinates to a drawing routine might be such a case: the coordinate pair has no independent existence, it has no identity, it is used only once and then immediately discarded, etc.
If this is the case, then sure, go ahead and pass two
ints rather than wrap them into an object. The point of OOP is not that everything must be an object. The point is that objects make development easier in places where they are the natural solution to a data representation problem. Don’t avoid objects where they make sense – don’t introduce them where they don’t.
When contemplating impacts on performance before you’ve written code you should assume you don’t know what you’re doing.
There is a very small space overhead for objects in java versus primitives. The tinier your objects are, the larger the percentage of overhead will be. However, I learned long ago that things that double n are nothing compared to things that multiply n by n.
So while yes you could finagle some system that had half the size impact or even a fourth please ask yourself why you really care. Complicated solutions to this problem are not going to be well received. Particularly because diving into such code will be confusing. Confused programmers write bad code. They write n times n code that should be n log n code. And they take longer to do it.
Now if you can save me space with some trick that fits in a nice box that I don’t have to look inside most of the time we can talk. If it’s a box I can swap out for another box when that box would work better I may even pay for it.
In the performance tuning I’ve done (example) it is very easy for memory management to be a major culprit. I don’t care how madly they’ve tuned the new operator and the garbage collector, the fastest computation is no computation.
So if I find the memory manager takes a good percent of time, and I can’t avoid making objects, then I find a way to re-use them, rather than constantly making new ones.
I only do this if I have to make objects.
For graphics, usually I don’t.
IMHO, graphics should be drawn, not built.
Sure, you could say that a picture consists of points, lines that connect them, polygons, text, and so on.
That doesn’t mean you have no alternative to making objects out of them before you draw them.
I just draw them.
There’s a Paint method.
I override that, draw everything to a bitmap, and then block transfer it to the screen. It looks instantaneous.
For mouse input, there are methods to override, to detect clicking, dragging, whatever.
OOP is a good idea for certain reasons.
Those reasons don’t apply in all situations.
Go ahead and use small allocations. Modern memory managers, particularly the highly optimized Java object manager, are extremely efficient. Save major performance optimization for a working program.
It is extremely likely that the overall performance will be adequate. If you find that is not the case, then, and only then, profile the code’s performance. In a long career of software development, I’ve learned that the bottlenecks are almost never where you expect.
I once had a team member spend several days making object member lookup 20x faster. Success! However, the best overall speedup in actual use was measured in hundredths of a percent. The change was immediately backed out, since the speedup required larger per member memory allocations.
It’s simple: If you need 1000 small objects, then you create 1000 small objects and don’t worry about it. If you need 100 small objects, then creating 1000 small objects is stupid – create the ones that you need and not more.
If you are worried about performance (and if you are not worried about performance as well) you should have any functionality written once in one place, which makes your whole code simpler and easier to understand. Then if you have a performance problem, then measuring may show you that there is one place where the performance problem happens, which makes things easier, and only one place where you need to change it. Or measuring shows that this one place doesn’t cause any problems, so you’re done.