http://qs321.pair.com?node_id=194638


in reply to Memory Use/Garbage Collection: Java vs Perl

I don't think garbage collection has anything to do with this at all.

In both cases, each sub doesn't return until its child has returned. As there is no limiting mechanism, no child ever returns! Therefore nothing is ever marked (unmarked) as free, so the garbage collector never has a chance to do anything?

Basically, you are simply recursing off the end of the stack in both programs.

If you want to test garbage collection, you need to throw some objects away, so that the gc has something to do.

One possible (and I emphasis possible, I know nothing of the internals of either) cause for some of the difference, is that Java is threadsafe. This implies a rather heavier stack usage than with non-threadsafe Perl?

In the Java version you are also concatenating string objects. Three times!

You start with the string (constant) "I am '", this is copied and concatenated with the stringified me, this is then copied to another and concatenated with the string "'!". That's 5 strings being created to print that one line. You should be using a StringBuffer to build this string. Or simply outputing the 3 bits as seperate strings. This is the most basic, and frequent mistake Java beginners make.

The Perl version will use it DWIM and intelligent compiling to build a single entity at the same point.

Like you said, a strong case of horses eating apples!


Well It's better than the Abottoire, but Yorkshire!

Replies are listed 'Best First'.
Re: Re: Memory Use/Garbage Collection: Java vs Perl
by agentv (Friar) on Sep 03, 2002 at 14:14 UTC

    ...you're right about this BrowserUK. Garbage collection doesn't get a chance to shine here. This was really a stack overflow test.

    To answer part of the originally posed question here, yes, Java does have some problems with it. Expect object overhead to be greater than in Perl. (In Perl, we simply string some things together and declare them an object. And that's very appropriate for our style of doing things.)

    In Java, there is a significant workload associated with creation of an object. Issues such as security and multithreading are important in that setting.

    Were we to address some of the same concerns in Perl, we'd have to provide that infrastructure for ourselves. And that's okay. It would probably be "just as much as we needed," for that is the strategy for object creation in Perl.

    Each has its place. If I have to put five people to work designing and implementing parts of a system that will have to be integrated, I think I want them using a discipline that enforces somewhat rigid conventions.

    If I have to put one really bright programmer to work at implementing a system that will be running quickly, I want a programming model that gives me just as much as I need, and stated in just about any fashion that makes sense to me.

    Or perhaps:

    ++$perl if $rapid_development > 2; # we need it fast ++$perl if $developers <= 2; # we have a small dev team ++$java if $threadsafe > 2; # we plan heavy thread use ++$java if $foreign_objects > 2; # untrusted objects print $perl >= $java ? "perl" : "java";

    You can use Perl for anything under the sun. But perhaps not everyone should try.

    ...All the world looks like -well- all the world, when your hammer is Perl.
    ---v

      I agree with some reservations.

      A good systems analyst (Note: Singular, not 'design commitee'!), should be able to partition pretty much any system into chunks and allocate those chunks to teams of two, who then exclusively (of other people rather than projects) work on designing and implementing those chuncks.

      I say teams of two (up to 4 I think is ok) rather than gifted individuals, as I think even the most gifted individual benefits from and sometimes needs someone to point out his assumptions and blind-spots.

      We've all encountered the lone-programmer who can churn out reams of working, tight, efficient code. They often have the ability to juggle several projects simulatenously. However, with rare exceptions, I would rather not be the one that has to go back and try to modify their code.

      The whole design-by-commitee thing is a real bug-bear of mine. My favorite example of why software should never be designed by committee, is the english language.

      Designed by (one-of) the biggest 'committies' in history, it is an eternally fascinating subject for philosophers, writers, critics, historians et al. (eg. pretty much the whole BA side of learning), but it has no real place except that of defacto-standard in most BSc. subject areas.

      This is exampled by the whole 'the sound of ...ough' thing (with tough, though, through, bough, cough, hough, lough).

      Personally I don't (yet) see any real reason a large project shouldn't be written in Perl, given proper analysis up front and on-going peer review of the code, but then I'm still learning (Perl).


      Well It's better than the Abottoire, but Yorkshire!
Re: Re: Memory Use/Garbage Collection: Java vs Perl
by charnos (Friar) on Sep 03, 2002 at 12:59 UTC
    I originally was writing a question as to how throwing away string objects in Java was handled, and whether or not the 4 unused strings out of the 5 created were destroyed, but then I tripped over this line in the J2SE 1.4 API docs: "The Java language provides special support for the string concatentation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuffer class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java." I did some digging on java.sun.com, and that line is verbatim in every API dating back to JDK v1.1. So it appears as though a println() call using the + operator looks like this:
    System.out.println(((new StringBuffer("I am'")).append(me.toString())) +.toString());
    to the compiler (the last toString() because a PrintStream doesn't have a println() method that takes a StringBuffer). I was taught even in my first CS class (we learned Java) that strings worked the way you said, and I was under that assumption until about five minutes ago. Perhaps I am wrong, but in my reading of the docs it appears that Java handles string concatentation with the + operator as you suggested he try manually.

      You make a very good point! My bad on that bit.

      <excuses>

      I did say <cite>I think...</cite>

      What do you expect at a Perl site? Java expertise :8^)...

      </excuses>

      Being serious for a moment, if Javac is 'doing the right thing' on that line, that just means that it's memory overhead on recursive subroutines must be even worse than I thought. 4,000 -v- 2,000,000 recursions before blowing the stack is a mind-boggling 500 times less efficient in terms of memory/stack management. I guess I was looking for a rational explanation.

      Note: I have made no attempt to verify the numbers

      Update:I have confirmed that your assertion is true when using javac from jdk1.3.1 as follows

      import java.io.PrintStream; class dupme { public dupme(int i) { // 0 0:aload_0 // 1 1:invokespecial #1 <Method void Object()> // 2 4:getstatic #2 <Field PrintStream System.out> // 3 7:new #3 <Class StringBuffer> // 4 10:dup // 5 11:invokespecial #4 <Method void StringBuffer()> // 6 14:ldc1 #5 <String "I am '"> // 7 16:invokevirtual #6 <Method StringBuffer StringBuffe +r.append(String)> // 8 19:iload_1 // 9 20:invokevirtual #7 <Method StringBuffer StringBuffe +r.append(int)> // 10 23:ldc1 #8 <String "'!"> // 11 25:invokevirtual #6 <Method StringBuffer StringBuffe +r.append(String)> // 12 28:invokevirtual #9 <Method String StringBuffer.toSt +ring()> // 13 31:invokevirtual #10 <Method void PrintStream.println +(String)> // 14 34:new #11 <Class dupme> // 15 37:dup // 16 38:iload_1 // 17 39:iconst_1 // 18 40:iadd // 19 41:invokespecial #12 <Method void dupme(int)> // 20 44:astore_2 // 21 45:return } }

      Well It's better than the Abottoire, but Yorkshire!
        The Perl version needs to concatenate strings, too!
        perl -MO=Deparse,-q -e"print qq(I am $x\n)"
        produces
        print 'I am ' . $x . "\n";
        not print ('I am ' , $x , "\n" ).

        That is, Perl concatenates the literals and variables together into one string, then calls print with the result.

        —John

        this whole thread is pretty OT, so i won't let that stop me from pointing out...

        You aren't garunteed to get the behavior you are seeing from every implimentation of Java -- the JLS only requires that string concatination must be implimented using a StringBuffer, not that multiple string concatenations must be optimized into a single StringBuffer.

        ie...

        this... String foo = "bar" + "baz"; is garunteed to be equivilent to this... StringBuffer tmp = new StringBuffer("bar"); tmp.append("baz"); String foo = tmp.toString(); But this... String wb = "yakko" + "wakko" + "dot"; might be implimented as... StringBuffer tmp1 = new StringBuffer("yakko"); tmp1.append("wakko"); String tmp2 = tmp1.toString(); StringBuffer tmp3 = new StringBuffer(tmp2); tmp3.append("dot"); String wb = tmp3.toString();

        You might want to check out JDC TechTip 2002-03-05 particularly it's discussion of "a statement found in the Java Language Specification section 15.18.1.2"