lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



On Sep 6, 2013 4:02 AM, "Sean Conner" <sean@conman.org> wrote:
>
> It was thus said that the Great Andres Perera once stated:
> > On Sep 5, 2013 10:53 PM, "Tim Hill" <drtimhill@gmail.com> wrote:
> > […]
> > > As for malloc(), nope, not confused at all, and while I am making a
> > > general assumption about malloc(), I've yet to find a help allocator
> > > underneath the C malloc() API that only allocates multiples of VM pages
> > > (I'm not sure when you mean "greater" granularity of you mean finer or
> > > coarser grained).
> >
> > Sigh.
> >
> > Whether or not malloc() organizes objects into buckets sized n^2, malloc()
> > can only acquire multiples of pagesize of virtual memory at a time. One
> > page can hold multiple objects.
> >
> > In function ``f'',
> >
> > int f()
> > {
> >     /*pa*/
> >     z = malloc(x);
> >     /*pb*/
> > }
> >
> > f at pa the process has allocated n bytes, and malloc(x) is successful,
> > then at pb the process vm will be  (n + x + PAGESIZE-1) & ~(PAGESIZE-1), in
> > other words, rounded to the nearest greater pagesize multiple.
>

Below you've written a nicer rundown that takes in account common syscall-reducing optimizations.

It's easy to see that malloc behavior potentially varies to a greater degree than architecture vm specs wrt fixed minimal allocation.

At least you recognize the difference between minimal allocation and size separated pools.

> int f(void)
> {
>   void *p[10];
>
>   p[0] = malloc(10);
>
>   /*--------------------------------
>   ;
>   ; At this point, let's assume that malloc() had to allocate some more
>   ; memory from the operating system.  Under Unix, this can be done via
>   ; brk()/sbrk() (older Unix systems) or mmap() (modern Unix systems).
>   ; brk()/sbrk() increase the size of the data segment, which *may* cause a
>   ; page to be allocated, but you are assuming that a generic Unix system is
>   ; paged---not all were.
>   ;
>   ; But that's somewhat academic---let's just go with a modern system using
>   ; mmap() to provide backing memory pages.  And in this case, let's use a
>   ; 32-bit system with 4K page sizes.  So now, the underlying malloc()
>   ; implementation has increased the virtual memory size of the process by a
>   ; page.
>   ;
>   ; There is some overhead that malloc() uses, so our 10 byte structure
>   ; probably has an additional 4 bytes allocated to indicate the size of the
>   ; block, we we are now up to 14 bytes, plus padding bytes to ensure
>   ; alignment and let's go easy and say we can align everything on a 4-byte
>   ; boundary, so our overhead for this 10-byte block is 6 bytes for a total
>   ; of 16 bytes used in the 4k page just freshly allocated.
>   ;
>   ;------------------------------------------*/
>
>   p[1] = malloc(10);
>
>   /*------------------------------------------------------------
>   ; there's no need for malloc() to allocate a new page, since this will
>   ; easily fit in the remaining space.  So, mark off another 16 bytes (6
>   ; bytes overhead, 10 bytes actual allocation).
>   ;------------------------------------------------------------*/
>
>   p[2] = malloc(10);
>
>   /*----------------------------------------------
>   ; same as p[1].  Nothing to see, move along
>   ;----------------------------------------------*/
>
>   free(p[1]);
>
>   /*--------------------------------------------------------
>   ; malloc() now marks the 16 (6 overhead, 10 allocated) as free, available
>   ; to be reallocated, if an allocation request that can be satisfied is
>   ; made.
>   ;------------------------------------------------------------*/
>
>   p[3] = malloc(25);
>
>   /*------------------------------------------------------------
>   ; Now here's where things get interesting.  malloc() can't use the the
>   ; recently released space since it's not large enough to fulfill the
>   ; request.  So it has to eat some more space out of the 4k.  25 bytes,
>   ; plus 4 for the size of the block is 29.  Again, because of alignment
>   ; issues, we need a few bytes for padding, in this case, 3.  We've
>   ; allocated another 32 bytes in the 4k memory page.  So far, we have 16
>   ; (p[0]) plus 16 (p[2]) plus 32 (p[3]) for a total of 64 bytes allocated;
>   ; there is still 4,032 bytes free in the page in two segments---one 16
>   ; bytes in size (the freed p[1]) and 4,016 in the other segment.
>   ;-----------------------------------------------------------------*/
>
>   p[4] = malloc(8);
>
>   /*-------------------------------------------------------------------
>   ; Another interesting action.  We're asking for 8 bytes, which that
>   ; 16-byte free space will easily hold.  Plus the size overhead gives us 12
>   ; bytes, leaving a 4-byte free space, which isn't enough to satisfy any
>   ; other requests at all, so the entire space is given over to this request
>   ; (4 bytes wasted, even though we don't need padding as 4 bytes is too
>   ; small to hand out, given that the space on either side is taken up with
>   ; previous allocations).
>   ;---------------------------------------------------------------------*/
>
>   p[5] = malloc(4012);
>
>   /*----------------------------------------------------------------------
>   ; And here we suck up the rest of the page into a single allocation.
>   ;---------------------------------------------------------------------*/
>
>   free(p[0]);
>   p[6] = malloc(1);
>
>   /*------------------------------------------------------------------
>   ; We free up the first 16 bytes, then allocate 1 byte, but because of
>   ; alignment and size, gets upped to 8 bytes.
>   ;---------------------------------------------------------------------*/
>
>   free(p[2]);
>   free(p[3]);
>   free(p[4]);
>   free(p[5]);
>   free(p[6]);
>
>   /*-------------------------------------------------------------------
>   ; Here we've free all the memory we've allocated.  At this point, malloc()
>   ; could return the memory back to the operating system, or it could hold
>   ; onto it, in case we call malloc() again and thus, avoid the overhead of
>   ; going to the operating system if we can satisfy the request.
>   ;-----------------------------------------------------------------*/
> }
>
> This describes a simple malloc() implementation.  Others are more elaborate,
> creating pools of memory to satisfy allocations of certain sizes (say,
> certain pages will be carved out for allocations of 8 bytes or less, other
> pages for allocations between 8 and 32 bytes say, etc.).
>
> > Please show a system where this is false.
>
>   Certainly.  The AmigaOS.  Ran on a Motorola 68000 sans memory management
> unit and thus, no concept at all of a "page".  The OS memory allocation
> schemes had an overhead of 12 bytes, with a 4-byte memory alignment (so a
> system request for 1 byte would actually allocate 16 bytes).
>
>   Then there are systems that use the protected mode of the 80286.  Again,
> no concept of "pages"---and in sucy a system (say, OS/2 1.x) you could
> request from the OS a 1 byte region of memory and you would get, a literal 1
> byte region of memory that was fully protected (it used variable sized
> "segments").
>
>   So there *are* systems out there that do not have the concept of a "page".
>
>   Are they still in use?
>
>   Yes.
>
>   Are they indicative of modern systems?  Probably not, but you did ask for
> "a system".
>
>   -spc (Will belabor the inanimate equus pleonastically for food)
>
>
>