views:

270

answers:

5

I use to program mainly with C/C++, that's make me dealing with pointers and memory management daily. This days I'm trying to develop using other tools, such as Java, Python and Ruby.

The problem is that I keep thinking C++ style, I'm writing code as C++ usually written in almost every programming language, and the biggest problem is the memory management, I keep writing bad code using references in Java and just get as close as I can to the C++ style.

So I need 2 thinks here, one is to trust the garbage collector, let's say by seeing benchmarks and proofs that it's realy working in Java, and know what I should never do in order to get my code the best way it can be.

And the second think is knowing how to write other languages code. I mean I know what to do, I'm just never write the code as most Java or Python programmers usually do, are there any books for C++ programmers just to introduce me to the writing conventions? (by the way, forgive me for my English mistakes)

A: 

I think you should keep thinking C++ style. Object creation is expensive in Java, more so than in C++ since you don't have the option to allocate on the stack. Not sure if this is the answer you were looking for, though.

kotlinski
and not sure if it makes any sense either ;)
Bozho
Modern JVMs will automatically allocate on the stack when possible - http://www.ibm.com/developerworks/java/library/j-jtp09275.htmlAnd in fact object allocation is often cheaper in Java due to "smart" allocation / inlining.
Steven Schlansker
Object creation in Java is not expensive. It used to be, but now JVM utilizez generational GC, which helps a lot. http://www.ibm.com/developerworks/java/library/j-jtp01274.html
el.pescado
Object creation in Java nowadays takes 2 or 3 instructions which makes it more lightweight operation than the age-old `i++` example.
Esko
But for short lived objects in C++ the compiler eliminates the construction entirely, and uses registers for its member variables, so there is zero cost. Hence it's common in C++ to use temporary structs as functors as parameters to algorithms. There will be small overhead in Java, both to create any object used, and as it is limited to runtime polymorphism and so has more restrictive of when it can inline function calls.
Pete Kirkham
OK, so finally Java VM technology got this far. Way to go.
kotlinski
@Pete: And some JVMs also use register for fields even, see the article referenced in Steven's comment. With Java then the programmer does not even need to choose between a heap-based or stack-based (struct) object.
Kevin Brock
@Kevin so with some JVMs at best you get the optimisations that C++ makes. However, programs I've seen profiled do not do it, and the whole ethos of Java is external rather than internal iteration, so you do tend to see procedural for() loops rather than injecting an object into a container. When you do inject into a container, Java has to rely on virtual dispatch (sometimes vtable, sometimes typecase), so it cannot make as good optimisations, so I still disagree with this answer twice that thinking C++ style is both optimal is Java, or that C++ style involves avoiding short-lived objects.
Pete Kirkham
+8  A: 

Having a good intuition for memory usage and common leaks is a good thing in Java as well. That memory leaks are impossible in Java is a common misconception.

Someone who ignores careful memory management, will for instance quickly end up with large trees of dangling GUI components, reachable from listener lists in long lived models. (Been there, done that.)

Keep writing your code structurally, and don't "exploit" the fact that you can be lazy.

Another misconception is that the garbage collector is "slow". The algorithms are quite efficient and you should not worry about it until you've profiled your program. A good tool is JVisualVM (bundled with the JDK). That tool will show you CPU-profiling and can help you with possible memory leaks and track down unnecessary small temporary allocations.

aioobe
+1  A: 

Turn garbage collection logging on and view the results in GCViewer. This will show you how memory in your app is performing and if enough memory being cleaned up when the garbage collector runs.

GCViewer Screenshot

krock
in Java 1.5 and later, jconsole gives the same (or similar) info without needing GC logging, and can connect to running Java processes
CuriousPanda
+6  A: 

One difference to bear in mind is that in C++ the destructor can be used to clean up any kind of resource, not just memory (i.e. RAII). In Java you have to explicitly close files, sockets, datastore connections etc in a try - finally block. If you put resource cleanup code in a Java finalize method then it may get called at some indeterminate time in the future, or never, so is not recommended. So in some ways this puts a bigger burden on the programmer, not less.

Python is somewhere in between - you can use the 'with' statement to handle automatic cleanup for most resources.

The two problems in C++ memory management are memory leaks and trying to use an object that has already been destroyed. As others have pointed out you can also get memory leaks in Java (and Python) if you keep a reference to an object that you no longer need, which in turn may have references to other objects. Memory leaks in Java may be less frequent but when they do occur they can be much bigger than in C++. Judicious use of weak references can help, as well as assigning null to variables that are no longer needed. However this leads to the second problem - if you then try to use the variable you will get a NullPointerException. This is more helpful than the segmentation fault you would probably get in C++, but is still an issue.

So all the things you learnt about memory management in C++ still apply in Java, but you have to do it for other resources too.

Dave Kirby
Couldn't you use finalizes for closing files and stuff?
AndrejaKo
@AndrejaKo - I wrote about finalize but mistyped it as 'finally' - now corrected. To answer your question, no you can't, for the reasons explained above.
Dave Kirby
@AndrejaKo - no, finalizes are non-deterministic, you can easily run out of resources in this way.
Artyom
Thanks for the tip!
AndrejaKo
+2  A: 

I think I understand your mindset problem entirely, mostly because I have the exact opposite of it :)

What I'd suggest is trying to create a sort of a paradigm transition from C++ to Java to enable yourself to write more of the actual code instead of managing objects themselves.

To give a concrete example, I'd assume that in C++ there's are certain things you do at the beginning and at the end of the object life cycle which means that you should most likely wrap those into their own methods (not constructors/destructors, mind you!) and first sort of "train" yourself to use those explicitly in C++. Then, when moving to Java you can actually move over this method analogy quite easily with your other programming habits and instead of scratching your head with destructors and whatnot, just implement to base of those methods but leave them empty. This way you have a not-so-invisible mental marker for yourself that the object lifecycle is about to end and eventually when you sort of learn to trust that, you can remove it. You don't even have to worry about overhead, JVM will optimize away those redundant method calls anyway as long as the body of the method is empty.

The next step of this, of course, is to extend the same to primitive values and going further from object lifecycle to method granularity level. To really condense to what I mean, here's an example class with those mental helpers applied:

public class MentalHelpers {
    private MyFieldObject mfo;

    /**
     * Note the separate method for object creation.
     * This is actually good practice in general!
     */
    public MentalHelpers() {
        createObject();
    }

    private final void createObject() {
        mfo = new MyFieldObject();
    }

    private final void destroyObject() {
        // Do nothing! private or public, you decide.
    }

    public int incrementOne() {
        int i = 1;

        int ret = i++;

        freeInt(i);

        return ret;
    }

    private final freeInt(int i) {
        // Once again, do nothing!
    }
}

That's it, hopefully this is helpful.

Esko
Why is it good practice to have separate methods for object creation? I don't see any reason why it would be bad, but why would it be good, unless you are using non-memory resources that need to be set up?
AndrejaKo
@AndrejaKo: Allows for easier dependency injection and overriding (*especially in tests and why not when extending, too*) when constructing partial/complex objects which can only partly be mocked otherwise.
Esko