Large memory allocations
Janderson
ask at me.com
Sat Nov 15 13:35:09 PST 2008
bearophile wrote:
> While allocating lot of memory for a little memory-hungry program, I have found results that I don't understand. So I have written the following test programs. Maybe someone can give me some information on the matter.
> I am using a default install of a 32 bit Win XP with 2 GB RAM (so for example I can't allocate 3 GB of RAM). (I presume answers to my questions are Windows-related).
>
> From C (MinGW 4.2.1) this is about the largest memory block I can allocate (even it swaps and requires 7+ seconds to run), 1_920_000_000 bytes:
>
> #include "stdio.h"
> #include "stdlib.h"
> #define N 480000000
> int main() {
> unsigned int* a = (unsigned int*)malloc(N * sizeof(unsigned int));
> unsigned int i;
> if (a != NULL)
> for (i = 0; i < N; ++i)
> a[i] = i;
> else
> printf("null!");
> return 0;
> }
>
>
> But from D this is about the largest memory block I can allocate with std.c.stdlib.malloc, 1_644_000_000 bytes, do you know why the difference?
>
> //import std.gc: malloc;
> import std.c.stdlib: malloc;
> void main() {
> const uint N = 411_000_000;
> uint* a = cast(uint*)malloc(N * uint.sizeof);
> if (a !is null)
> for (uint i; i < N; ++i)
> a[i] = i;
> else
> printf("null!");
> }
>
> (If I use std.gc.malloc the situation is different yet, and generally worse).
>
> -----------------------
>
> So I have tried to use a sequence of smaller memory blocks, this is the C code (every block is about 1 MB):
>
> #include "stdio.h"
> #include "stdlib.h"
>
> #define N 250000
>
> int main(int argc, char** argv) {
> unsigned int i, j;
> unsigned int m = argc == 2 ? atoi(argv[1]) : 100;
>
> for (j = 0; j < m; ++j) {
> unsigned int* a = (unsigned int*)malloc(N * sizeof(unsigned int));
>
> if (a != NULL) {
> for (i = 0; i < N; ++i)
> a[i] = i;
> } else {
> printf("null! %d\n", j);
> break;
> }
> }
>
> return 0;
> }
>
>
> And the D code:
>
> //import std.gc: malloc;
> import std.c.stdlib: malloc;
> import std.conv: toUint;
>
> void main(string[] args) {
> const uint N = 250_000;
> uint m = toUint(args[1]);
>
> for (uint j; j < m; ++j) {
> uint* a = cast(uint*)malloc(N * uint.sizeof);
>
> if (a !is null) {
> for (uint i; i < N; ++i)
> a[i] = i;
> } else {
> printf("null! %d\n", j);
> break;
> }
> }
> }
>
> With such code I can allocate 1_708_000_000 bytes from D and up to 2_038_000_000 bytes from C (but near the last 100-200 MB of RAM the C code swaps a lot).
> So can't I can't use all my RAM from my D code? And do you know why?
>
> Bye,
> bearophile
bearophile wrote:
> While allocating lot of memory for a little memory-hungry program, I
have found results that I don't understand. So I have written the
following test programs. Maybe someone can give me some information on
the matter.
> I am using a default install of a 32 bit Win XP with 2 GB RAM (so for
example I can't allocate 3 GB of RAM). (I presume answers to my
questions are Windows-related).
>
> From C (MinGW 4.2.1) this is about the largest memory block I can
allocate (even it swaps and requires 7+ seconds to run), 1_920_000_000
bytes:
>
> #include "stdio.h"
> #include "stdlib.h"
> #define N 480000000
> int main() {
> unsigned int* a = (unsigned int*)malloc(N * sizeof(unsigned int));
> unsigned int i;
> if (a != NULL)
> for (i = 0; i < N; ++i)
> a[i] = i;
> else
> printf("null!");
> return 0;
> }
>
>
> But from D this is about the largest memory block I can allocate with
std.c.stdlib.malloc, 1_644_000_000 bytes, do you know why the difference?
>
> //import std.gc: malloc;
> import std.c.stdlib: malloc;
> void main() {
> const uint N = 411_000_000;
> uint* a = cast(uint*)malloc(N * uint.sizeof);
> if (a !is null)
> for (uint i; i < N; ++i)
> a[i] = i;
> else
> printf("null!");
> }
>
> (If I use std.gc.malloc the situation is different yet, and generally
worse).
>
> -----------------------
>
> So I have tried to use a sequence of smaller memory blocks, this is
the C code (every block is about 1 MB):
>
> #include "stdio.h"
> #include "stdlib.h"
>
> #define N 250000
>
> int main(int argc, char** argv) {
> unsigned int i, j;
> unsigned int m = argc == 2 ? atoi(argv[1]) : 100;
>
> for (j = 0; j < m; ++j) {
> unsigned int* a = (unsigned int*)malloc(N * sizeof(unsigned
int));
>
> if (a != NULL) {
> for (i = 0; i < N; ++i)
> a[i] = i;
> } else {
> printf("null! %d\n", j);
> break;
> }
> }
>
> return 0;
> }
>
>
> And the D code:
>
> //import std.gc: malloc;
> import std.c.stdlib: malloc;
> import std.conv: toUint;
>
> void main(string[] args) {
> const uint N = 250_000;
> uint m = toUint(args[1]);
>
> for (uint j; j < m; ++j) {
> uint* a = cast(uint*)malloc(N * uint.sizeof);
>
> if (a !is null) {
> for (uint i; i < N; ++i)
> a[i] = i;
> } else {
> printf("null! %d\n", j);
> break;
> }
> }
> }
>
> With such code I can allocate 1_708_000_000 bytes from D and up to
2_038_000_000 bytes from C (but near the last 100-200 MB of RAM the C
code swaps a lot).
> So can't I can't use all my RAM from my D code? And do you know why?
>
> Bye,
> bearophile
Different allocation schemes have different strengths and weaknesses.
Some are fast, some fragment less, some have less overhead, some allow
larger sized blocks. Often these things arn't mutual so there are
always tradoffs. For example, to improve speed an allocator may
allocate into particular buckets which might restrict the maximum size
of one allocation.
I wonder how Ned-Malloc or Hord perform with your tests?
-Joel
More information about the Digitalmars-d-learn
mailing list