Re: C++ vs Java "new" (no flame war please!)
- From: mlw <mlw@xxxxxxxxxxxxxx>
- Date: Mon, 02 Apr 2007 12:56:50 -0400
Lew wrote:
Lew wrote:
Let's assume you want to create N objects where N is the largest number
of such objects that would fit in available memory.
List <Foo> stuff = new ArrayList <Foo> (N);
mlw wrote:
That's one memory alloc, sure.
Lew wrote:
for ( int x = 0; x < N; ++x )
{
stuff.add( new Foo( getAString() ) );
}
mlw wrote:
The above code is exactly my problem with Java. In C++ I can overload new
and put all the objects anywhere I want, even in to one contiguous memory
block calling malloc merely once and combining the object and the string
in one allocation,
You still need to calculate offsets into that block to fix the start of
each
individual object. In fact, the code in your custom allocator uses more
memory and much more time than would the JVM for the equivalent Java
class.
That is simply not true on either account, I don't need to "fix" the start
of anything. There is no memory overhead for each class. The "allocation"
overhead time is nothing more than a simple integer addition.
Yes.
Every memory allocation has overhead, in GCC malloc, it is probably 4
bytes, 8 bytes on 64 bit systems. So, if you have fairly small objects,
and lots of them, a good chunk of memory will be eaten up with malloc
overhead. If you have a small object with a string, you will have two
memory allocations!
Your C++ class did a copy of the string.
A Java class likely would not,
since Strings are immutable, so it would only do one allocation for the
Foo object
and none for the String.
Well, not seen in the example would be that the string is read from a file
into a local buffer which gets reused.
Even if one did copy the String, the time
overhead of the Java allocation and copy would be much less than for the
C++ code you
showed.
How is this possible?
char buffer[MAX_SIZE]
while(!feof(f))
{
if(fgets(buffer, sizeof(buffer), f))
{
new(buffer) foo();
}
}
Where is the allocation overhead that you are referring too?
For one thing, the Java code would only loop through the String
once, not twice as in your C++ code; it would have no need to calculate
"strlen()".
The memory overhead would be no different since a copy is a copy is a
copy.
Like I said, I was showing a technique that was simplified for example,
don't nit-pick the example because it is obviously much less sophisticated
then the actual application that uses the technique. In the real code, the
new operator is much more complex and reads the data itself.
But as I said, the Java code would not copy the String, so the point is
moot. One allocation and less memory overhead in the Java version.
Java would allocate a new string for each string. My code does not issue any
memory allocation for the string, it comes from a fixed length block and it
is combined with the object proper.
Obviously this is a rare problem, but it is a problem none the less.
I don't see what the problem with Java is. What is the bad effect that
concerns you with Java?
Is it memory overhead? Objects in Java take up only as much space as they
take.
Try this:
allocate 20,000,000 objects with each object containing at least one string.
The memory footprint of the application has AT LEAST 160 megabytes of
overhead that can be virtually eliminated by pre-allocating 4 megabyte
blocks and sub-allocating out of that.
Is it time overhead? Java object allocations run on the order of 10-20
machine cycles. Initialization of the object takes some time, perhaps,
but that would be true with your custom allocator as well.
Java allocations take 10-20 machine cycles? Not on your life. In JIT
compiled code in which objects lose scope on exit of the function, yes,
that may be the overall time (it could even be much less), but objects that
live beyond a function scope have the overhead of a memory allocation.
Your description seems to delineate a problem with C++ that your custom
allocator handles, but I see nothing of this relevant to Java.
Java:
class foo
{
String m_test;
foo(String value)
{
m_test = value;
}
void print()
{
System.out.println(m_test+"\n");
}
};
public class test
{
public static void main(java.lang.String[] args)
{
int i=0;
try
{
foo arr[] = new foo[2000000];
for(i=0; i < 2000000; i++)
arr[i] = new foo(Integer.toHexString(i));
}
catch(OutOfMemoryError e)
{
System.out.println(e.getMessage());
System.out.println("Total object:" + i);
}
}
};
C++
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
class foo
{
char *m_test;
public:
foo();
void * operator new(size_t size, void *p, size_t cb);
};
#define BLKSIZE 1024*1024
unsigned char *block = NULL;
size_t blk_size=0;
size_t blk_offset=0;
foo::foo()
{
}
void *foo::operator new(size_t size, void *p, size_t cb)
{
size_t totalcb = size+cb;
if(!block || totalcb > (blk_size - blk_offset))
{
block = (unsigned char *) malloc(BLKSIZE);
blk_size = BLKSIZE;
blk_offset = 0;
}
assert(block);
foo *fooT = (foo *) &block[blk_offset];
blk_offset += size;
fooT->m_test = (char *) &block[blk_offset];
blk_offset += cb;
memcpy(fooT->m_test, p, cb);
return (void *) fooT;
}
int main()
{
int i=0;
foo ** ar = (foo **) malloc(sizeof(foo*) * 2000000);
for(i=0; i < 2000000; i++)
{
char buffer[64];
size_t cb = snprintf(buffer,sizeof(buffer), "%X", i)+1;
ar[i] = new((void *)buffer,cb) foo();
}
printf("%d\n", i);
}
The results:
test@localhost:~/scat$ time java test
Java heap space
Total object:914828
real 0m23.519s
user 0m21.009s
sys 0m2.004s
test@localhost:~/scat$ time ./test
2000000
real 0m0.838s
user 0m0.724s
sys 0m0.064s
.
- Follow-Ups:
- References:
- C++ vs Java "new" (no flame war please!)
- From: mlw
- Re: C++ vs Java "new" (no flame war please!)
- From: Lew
- Re: C++ vs Java "new" (no flame war please!)
- From: mlw
- Re: C++ vs Java "new" (no flame war please!)
- From: Lew
- C++ vs Java "new" (no flame war please!)
- Prev by Date: Re: C++ vs Java "new" (no flame war please!)
- Next by Date: Re: C++ vs Java "new" (no flame war please!)
- Previous by thread: Re: C++ vs Java "new" (no flame war please!)
- Next by thread: Re: C++ vs Java "new" (no flame war please!)
- Index(es):
Relevant Pages
|