Try measuring it with various allocators.
Some will try too hard and be "too smart" and will add extra cost, but most will try to get out of your way until/unless there are deallocations leaving holes.
They'll typically ask for a multiple of pages at a time, and some increase the number of pages requested each time. A quick check with strace right now shows modern glibc in my instance allocating about 2MB at the time when running "find" for example. It will do more if you ask for larger chunks of memory at the time, of course.
In term of fitting in, some allocators will segment the heap it requests into separate free lists, but many will do this first on deallocations to combat fragmentation. E.g. here's a simple example that shows objects linearly allocated on the heap (on my system, anyway) despite different sizes:
int main () {
void * a, * b, *c, *d;
a = malloc(4);
b = malloc(8);
c = malloc(12);
d = malloc(16);
printf("a=%p\nb=%p\nc=%p\nd=%p\n", a,b,c,d);
}
$ ./test
a=0x1a7d010
b=0x1a7d030
c=0x1a7d050
d=0x1a7d070
Increasing the size of c and d to 64 and 128 bytes respectively to get over the alignment size, I get:
$ ./test
a=0x1678010
b=0x1678030
c=0x1678050
d=0x16780a0
So still allocating linearly at those, admittedly still small size allocations.
In this case, the cost of doing the allocation typically boils down to seeing if there is space in one of the free lists, then if there's space at the high water mark of the current heap allocation, and only if there is not do another system call. When there is space, the cost tends to be a few comparisons, adding some book-keeping details, and increasing a pointer. It's extremely rare to even show up when profiling.
So the cost of those syscalls tends to get amortized over enough allocations that the cost is negligible. E.g. with my example above, glibc does a single allocation to cover the 4 allocations I did.
For a process that only ever allocates, the number of system calls will depend on how aggressive the allocator is about growing the size of the extra memory it requests, but in general the number of syscalls will be small.
I appreciate the attention to syscalls - it's a pet peeve of mine that people tend to think library calls are cheap, without realising the cost difference between a mostly user-space one vs. ones that do a syscall and hence context switch every time (read() and write() are particularly persistently abused - add buffering, people), but malloc() or C++ new are rarely amongst them (doesn't mean you should do lots of tiny ones, though; if you do, profile and consider a pool allocator).