-5

I've just realised that when I am programming in Java I avoid local variables like the plague, if I really have to I prefix a member with a lower case "L" and have a method that resets that object (if the object is mine, I usually have a private method called init or something that the constructor calls)

I've just realised that this is really ugly in so many ways. Am I doing it right?

C++ programmers will know exactly what I mean, locals that don't leave the function's scope are automatically destroyed for us (if it does leave the function scope, use a pointer, blah blah blah)

Pattern for when this happens

I've found that whenever I fit an adapter to a function parameter and interact with it through this adapter is when I use this.

I also tend tohave the adapter maintain a pool of any objects it uses (up to a certain number)

It also occurs when I want to use data-types that require "new" to initialise but only within the method.

The code is a part of some main loop usually, otherwise it wouldn't matter, obviously (it's not a one off thing)

GC Collection amount:
Amount (Mb):  |   30|   60|   90|  120|  150|  180|  210|  240|  270|  300|  330|  360|
--------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
With pattern  |## (14)
without       |################################################################### (350)

The program was pushed through its unit tests the mean GC amount is shown. The standard deviation was less than 5 for both.

This feels like it is somehow related to the flywheel pattern...

There is no code for this because:

It can manifest itself in so many ways! If you have a ComplexNumber class for example, if you just create them as needed you will generate vast amounts of garbage, if you have any sort of vector or matrix classes, same thing.

Another area is anything involving some sort of graph which is carefully traversed to generate another structure, like a scene graph, critical path, even a stack representing the current directory.

Basically if you have "new" to assign to a local variable in a method that gets called a lot you will find this.

Sample used above

It came from a program I wrote to teach people about finite state automata and other state-machines (Markov Chains, so forth), I noticed crippling ram usage and decided to investigate.

Comparison with other languages

Obviously C++ doesn't have this problem. But nor does Python you'll be glad to know. Python's reference counting means (provided you haven't got any cricles) that the moment the method ends things are deleted, infact there is a meta-method for it and you can use it reliably as a destructor (provided you are disciplined enough not to leak it from the method)

I can't be the first to have this problem, looking at similar questions suggests that there is no solution, but I can't believe that this hasn't been encountered before!

About me

I'm coming from C++ and Python (love them both!) to Java, I am "experienced" in Java in that I can read/write stuff that works, it follows a nice design philosophy and such, but I tend to be very mindful of performance and resources. I'm suffering withdrawal from const, I was a total const whore.

How this is not pooling

Suppose you have a GroupElement class - that represents a member of an algebraic group, we'll use additive notation.

Suppose that g.add(h) returns a new element, if you do this MANY many times you have a lot of elements. if instead you have:

 GroupElement f = new GroupElement(0); //identity
 g.add(f,h); 

where:

add's first argument is the place to put the result, we generate no garbage.

The people who don't follow the above

You should know what a complex number is? Suppose a complex number has a method called add that takes a complex number and returns a new complex number. If you do a=b.add(c); A LOT of times, you get A LOT minus 1 garbage complex numbers floating around.

If you have inplaceAdd(ComplexNumber target, ComplexNumber value) say where:

target.real = value.real+real;
target.im = value.im+im;

you create no garbage if you do: b.inplaceAdd(a,c) - which does the same as the above a=b.add(c)

BTW add could do this: return new ComplexNumber(real+value.real,im+value.im) - see what I mean now?

Implementation of example (seriously guys, how do you not get this!)

public class ComplexNumber {
    private double real;
    private double im;

    public ComplexNumber(double r, double i) {
        real = r;
        im = i;
    }

    public ComplexNumber add(ComplexNumber value) {
        return new ComplexNumber(real + value.real, im + value.im);
    }

    public void inplaceAdd(ComplexNumber target, ComplexNumber value) {
        target.real = real + value.real;
        target.im = im + value.im;
    }
}
Alec Teal
  • 5,770
  • 3
  • 23
  • 50
  • 1
    I have purged all the comments as they were getting out of hand. @LuiggiMendoza please stop Americanising all the spellings. – ChrisF Dec 10 '13 at 09:43
  • 1
    @ChrisF *Americanizing :) – Alec Teal Dec 10 '13 at 17:56
  • 2
    BTW, even if there were actually a good reason for to have a `void`-returning three-argument `add` (addend #1, addend #2, destination), I think a signature like `public void setToSumOf(final ComplexNumber... numbers)` would be much more readable. – ruakh Dec 10 '13 at 19:01

1 Answers1

3

If you have a ComplexNumber class for example, if you just create them as needed you will generate vast amounts of garbage, if you have any sort of vector or matrix classes, same thing.

Keep in mind that garbage is free; the cost of garbage collection is determined by the non-garbage that has to be traversed. (I mean, the VM spec doesn't actually specify exactly how GC must be implemented, but that's how the major ones all work.) And this is intentional: obviously there's no technical reason that a Java implementation can't use reference-counting; it's just that it's not considered very robust/efficient/reliable/etc. (In C++ and Perl and Python, the reference-counting gives you the advantage of predictable destructors. Java doesn't offer that; instead, it offers finally blocks and try-with-resources.)

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • See the edit at the bottom of my post, it explains what I mean. – Alec Teal Dec 10 '13 at 05:58
  • 2
    @AlecTeal: Sorry, I don't really understand your edit -- it seems that you've just moved the `new` from one piece of code to another, without actually affecting the number of allocations -- but either way, the answer is the same. There is no reason to reuse objects, because short-lived objects are not expensive. – ruakh Dec 10 '13 at 06:01
  • You aren't doing what you think you are doing with that code, depending on what types the arguments are. –  Dec 10 '13 at 06:03
  • @JarrodRoberson see the edit at the bottom. I don't know how you guys don't get this. There are closes and downvotes! It's madness! How have you not had this problem before! – Alec Teal Dec 10 '13 at 06:08
  • 6
    ***Because it isn't a problem, that is why.*** Unless you show the entire code for this magical `ComplexNumber` class it is all a moot point anyway. Object creation is free in Java, and Java is **NOT** C++ or Python. You are conflating a problem that does not exist based on a lack of understanding of how the Garbage Collector works in Java. –  Dec 10 '13 at 06:11
  • 2
    @AlecTeal because it is not a problem (at least not for us) since the GC already handles memory management for us. The only thing we should worry is to not generate memory leaks with our code, because not even the GC would help us there. – Luiggi Mendoza Dec 10 '13 at 06:11
  • @JarrodRoberson the problem DOES exist, 350mb roller-coaster has been MEASURED, it can be fixed by creating less nice code, is that the correct way or not. – Alec Teal Dec 10 '13 at 06:28
  • What is the problem, does your program crash? Does it run un-acceptably slow? What? You are describing *works as designed behavior*, you have not in this entire rant post, given a single reason that this is *bad* other than you think it is? –  Dec 10 '13 at 06:31
  • @JarrodRoberson .... using lots more ram than is needed is bad because it forces the OS to page out things that the user(S) might be using. In my case this was bad, so I found a way to stop the roller-coaster ram graph at the cost of code-clarity, now it works - I want to know "if I'm doing it right" because the problem of huge GC build up has surely been encountered before. I have no idea why there are so many weird / offtopic replies to this stuff. – Alec Teal Dec 10 '13 at 06:52
  • 2
    No you are **not** *doing it right*. There everyone else has said it a dozen different ways. ***There is no problem of huge GC build up***, you are using more RAM that your system has, which is causing Paging, what you are doing is treating a symptom and not the cure. The cure is to not hold on to things as long as you are, plain and simple; Unused objects don't cause the system to page, only referenced objects do! I just whipped up this [demo code](https://gist.github.com/jarrodhroberson/7886811) it is pretty much every worst practice when it comes to memory management in Java, it runs fine. –  Dec 10 '13 at 07:13
  • Read [this](http://stackoverflow.com/questions/11768615/jvm-memory-usage-out-of-control/11769540#11769540) and [this](http://stackoverflow.com/questions/12306181/windows-memory-raising/12306449#12306449) and [this](http://stackoverflow.com/questions/9145769/limit-jvm-process-memory-on-ubuntu/9146775#9146775). If you are having problems with Paging your *solution* isn't going to solve the root cause. Reducing memory consumption in the JVM is **all about release references** and **not** about not generating objects to begin with. –  Dec 10 '13 at 07:15