Recent

Author Topic: FPC memory manager vs C std library  (Read 5084 times)

Ryan J

  • Full Member
  • ***
  • Posts: 141
FPC memory manager vs C std library
« on: July 24, 2023, 04:49:22 am »
Curious, are there any advantages to using the FPC memory manager instead of malloc etc...? I've never used the C library before but I was thinking maybe there are more tools available for it? I have to think with all the manpower behind C their implementation would be faster, true or false?

For one example there appears to be a bug in heaptrc on Apple silicon which causes the stack traces to only memory addresses so maybe I could opt in to the C library?

BrunoK

  • Hero Member
  • *****
  • Posts: 766
  • Retired programmer
Re: FPC memory manager vs C std library
« Reply #1 on: July 24, 2023, 06:42:19 am »
Select search button.
Type cmem as search term.
Ask items ordered recent to old.

Read discussions !

Red_prig

  • Full Member
  • ***
  • Posts: 153
Re: FPC memory manager vs C std library
« Reply #2 on: July 24, 2023, 09:41:19 am »
If I remember correctly, it is recommended to use the standard FPC memory manager in windows and cmem for unix/linux

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12706
  • FPC developer.
Re: FPC memory manager vs C std library
« Reply #3 on: July 24, 2023, 11:13:14 am »
No. Recommended is the standard memory manager always. 

CMem was mainly implemented for broken SO/dll libs that might free your pascal allocated pointer and vice versa (required you to free a pointer allocated inside the library), because it made C and pascal pointers (for non automated types) compatible.

Some also advocate performance benefits, but it is no clear in which scenarios and on which targets it _really_ matters, nitpicking aside. Most evidence is anecdotal with one example that usually stresses one aspect heavily.

« Last Edit: July 24, 2023, 08:54:01 pm by marcov »

Warfley

  • Hero Member
  • *****
  • Posts: 2039
Re: FPC memory manager vs C std library
« Reply #4 on: July 24, 2023, 11:33:54 am »
The FPC memory manager tends to "over allocate" memory blocks, because it uses different memory blocks for different allocation sizes:
Code: Pascal  [Select][+][-]
  1. var
  2.   p: Pointer;
  3. begin
  4.   Getmem(p, 4);
  5.   WriteLn(IntPtr(p)); // 22266864
  6.   Freemem(p);
  7.   Getmem(p, 128);
  8.   WriteLn(IntPtr(p)); // 22332304
  9.   Freemem(p);
  10. end.  
As you can see the allocation for 4 bytes is in a completely different memory area than the 128 byte allocation.
When using the C Memory manager isntead:
Code: Pascal  [Select][+][-]
  1. uses
  2.   cmem,
  3.   Classes;
  4.  
  5. var
  6.   p: Pointer;
  7. begin
  8.   Getmem(p, 4);
  9.   WriteLn(IntPtr(p)); // 1855288
  10.   Freemem(p);
  11.   Getmem(p, 128);
  12.   WriteLn(IntPtr(p)); // 1855288
  13.   Freemem(p);
  14. end.
Both allocations are on the same memory area.

If I remember correctly this is built this way to avoid fragmentation. The C memory manager is a first come first serve memory manager, where basically the memory will be allocated like a stack. This suffers heavily from fragmentation. Meaning if you have small allocations in between larger allocations freeing those small allocation will leave "holes" between the larger ones, that cannot be re-used by larger allocations. This means searching for a new free allocation requires you to go through each of these holes and check if it fits the required memory.
This of course is much easier with the FPC memory manager, as it has different lists for small and large allocations they can never be intermixed.

This results in the FPC memory manager being much more complex and needing to perform more OS level allocations for each of those allocation areas individually, which makes it comparatively slow, and also it requires more memory in general.
The extremely simple design of the C memory manager, in combination with the highly optimized implementation in the libc (which has processor specific optimizations for all major CPUs) makes it really fast. Also in the best case it will allocate always exactly as much memory as it needs and never overallocates. This means it can be much more efficient. That said, when you have fragmentation all these advantages can quickly vanish. With small unusable "holes" the memory utilization will be less than optimal, and requiring to traverse all of these holes to find a memory area that fits can take a lot of time when there are alot of holes.

So while it can be faster, if it really is in a real world scenario depends on the code it is used in and the levels of memory fragmentation it encounters.

Thaddy

  • Hero Member
  • *****
  • Posts: 18764
  • To Europe: simply sell USA bonds: dollar collapses
Re: FPC memory manager vs C std library
« Reply #5 on: July 24, 2023, 11:40:05 am »
The implementation of a C memory manager differs per compiler implementation and is often far more complex and efficient compared to the CMem in the original implementation.
With that in mind it still holds that the default FPC memory manager favors size over speed, but more modern C memory managers can implement patterns that offer a compromise between speed and size too.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

BrunoK

  • Hero Member
  • *****
  • Posts: 766
  • Retired programmer
Re: FPC memory manager vs C std library
« Reply #6 on: July 24, 2023, 02:09:21 pm »
And in multi-threading applications, using cmem, memory allocated by one thread can be freed by another thread and return the freed memory for reuse. As verified by a benchmark disparaged by some local Hero a few years ago.

Thaddy

  • Hero Member
  • *****
  • Posts: 18764
  • To Europe: simply sell USA bonds: dollar collapses
Re: FPC memory manager vs C std library
« Reply #7 on: July 24, 2023, 02:15:29 pm »
Correct, but that is also considered an anti-pattern and not all C  memory managers do that: so it is even in C a crime to port over different compilers and platforms.
It is an anti-pattern because memory allocation relies on ownership:
A piece of code that wants to free memory allocated by another piece of code should just signal that piece, not simply do the de-allocation by itself. IOW the allocating code should also de-allocate that memory.
« Last Edit: July 24, 2023, 02:27:21 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

abouchez

  • Full Member
  • ***
  • Posts: 135
    • Synopse
Re: FPC memory manager vs C std library
« Reply #8 on: July 24, 2023, 06:40:14 pm »
Curious, are there any advantages to using the FPC memory manager instead of malloc etc...? I've never used the C library before but I was thinking maybe there are more tools available for it? I have to think with all the manpower behind C their implementation would be faster, true or false?
The FPC MM is clean, simple and cross-platform. It is just fine in most common cases. For a LCL GUI app, it is pretty good.
The cmem unit redirects to the libc malloc/free. The implementation in the GNU libc is very efficient, especially on multi-thread process. From real world benchmarks, e.g. of a REST server doing non trivial process, using the libc allocator scales better.
I have written the https://github.com/synopse/mORMot2/blob/master/src/core/mormot.core.fpclibcmm.pas wrapper which uses less memory than the standard cmem, which is a bit outdated so does not take into account the msize API call.
For x86_64 CPUs (Windows or Linux), I prefer my own https://github.com/synopse/mORMot2/blob/master/src/core/mormot.core.fpcx64mm.pas with tuned assembly which is faster than both - unless you have very high-end HW process with dozen of concurrent cores/threads running, in which case the libc MM scales slightly better.

But the main problem with calling the libc/cmem is that any invalid pointer operation would not only GPF the process, but call a libc panic, i.e. quit/abort/sigkill the process execution...  :o
Whereas the FPC MM or our fpcx64mm unit don't panic, just GPF, so you are likely to be able to continue your process, even if your own code is not correct.
In practice, it may be very difficult to track memory bugs e.g.  duplicated freemem calls, in server process, or if you depend on third-party code or components which may have a strange behavior.
So I would advice against using cmem in practice, unless you really know what you are doing, and with a very proven and stable code. There is nothing worse than a process suicide without prior notice in a middle of a process, especially on shared service.

Quote from: Ryan J
For one example there appears to be a bug in heaptrc on Apple silicon which causes the stack traces to only memory addresses so maybe I could opt in to the C library?
When using heaptrc, there is no benefit of using cmem. I don't understand what you mean about this bug.
« Last Edit: July 24, 2023, 06:51:48 pm by abouchez »

Ryan J

  • Full Member
  • ***
  • Posts: 141
Re: FPC memory manager vs C std library
« Reply #9 on: July 30, 2023, 04:47:04 am »
Quote
But the main problem with calling the libc/cmem is that any invalid pointer operation would not only GPF the process, but call a libc panic, i.e. quit/abort/sigkill the process execution...  :o
Whereas the FPC MM or our fpcx64mm unit don't panic, just GPF, so you are likely to be able to continue your process, even if your own code is not correct.
In practice, it may be very difficult to track memory bugs e.g.  duplicated freemem calls, in server process, or if you depend on third-party code or components which may have a strange behavior.
So I would advice against using cmem in practice, unless you really know what you are doing, and with a very proven and stable code. There is nothing worse than a process suicide without prior notice in a middle of a process, especially on shared service.

Sorry for the late reply! This is interesting to me,

1) why is it good the FPC manager fails without crashing the program? Doesn't this mean your programs state is corrupted now and not usable? I don't see why it's good the program continues to run in this state.

2) If it's good enough for C/C++ why isn't it good enough for Pascal? I have to think these two designs have pro's and cons.

Ryan J

  • Full Member
  • ***
  • Posts: 141
Re: FPC memory manager vs C std library
« Reply #10 on: July 30, 2023, 04:51:46 am »
This results in the FPC memory manager being much more complex and needing to perform more OS level allocations for each of those allocation areas individually, which makes it comparatively slow, and also it requires more memory in general.
The extremely simple design of the C memory manager, in combination with the highly optimized implementation in the libc (which has processor specific optimizations for all major CPUs) makes it really fast. Also in the best case it will allocate always exactly as much memory as it needs and never overallocates. This means it can be much more efficient. That said, when you have fragmentation all these advantages can quickly vanish. With small unusable "holes" the memory utilization will be less than optimal, and requiring to traverse all of these holes to find a memory area that fits can take a lot of time when there are alot of holes.

So while it can be faster, if it really is in a real world scenario depends on the code it is used in and the levels of memory fragmentation it encounters.

Thanks for your detailed response. This makes it sound like the C memory manager is probably better for single pass programs (like a compiler) while the FPC manger would be better for longer running processes?

I know C powers  server software though so it must be viable but maybe computers these days have so much memory it's not likely to get into heap fragmentation issues? I can also imagine a memory arena would be good with a stack as you could free the memory in batches in the same order as it was allocated in many instances.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12706
  • FPC developer.
Re: FPC memory manager vs C std library
« Reply #11 on: July 30, 2023, 01:33:11 pm »
2) If it's good enough for C/C++ why isn't it good enough for Pascal? I have to think these two designs have pro's and cons.

There are many alternative malloc implementations for C/C++. If it was so perfect, those wouldn't exist.

Keep in mind there is no "C" platform. OS X is likely different from Linux, which is again different from Windows.

Ryan J

  • Full Member
  • ***
  • Posts: 141
Re: FPC memory manager vs C std library
« Reply #12 on: July 30, 2023, 04:13:22 pm »
There are many alternative malloc implementations for C/C++. If it was so perfect, those wouldn't exist.

I didn't know that. Is there even a single memory manager for C++ or does each of the major C++ compilers provide their own memory manager also?

It really seems like there should be some unified cross language solution to a memory manager since it's something we all need.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: FPC memory manager vs C std library
« Reply #13 on: July 30, 2023, 04:55:57 pm »
Is there even a single memory manager for C++ or does each of the major C++ compilers provide their own memory manager also?
The latter. It's one of many areas where compilers compete and there's no point there for unification. And yes, don't forget the 3rd party attempts. There are also memory managers designed specifically to track (de)allocations to help with debugging memory leaks.

Warfley

  • Hero Member
  • *****
  • Posts: 2039
Re: FPC memory manager vs C std library
« Reply #14 on: July 30, 2023, 05:27:59 pm »
I know C powers  server software though so it must be viable but maybe computers these days have so much memory it's not likely to get into heap fragmentation issues? I can also imagine a memory arena would be good with a stack as you could free the memory in batches in the same order as it was allocated in many instances.
C and (modern) Pascal programs are very differently. As I have already mentioned in a previous thread, in Pascal you will often see people creating classes (which require memory allocation) for alot of ver small things. For example I have just written this function today:
Code: Pascal  [Select][+][-]
  1. var
  2.   JSONData: TJSONObject;
  3.   ProfilesFile: String;
  4.   JSONText: String;
  5.   fs: TFileStream;
  6. begin
  7.   ProfilesFile := ConcatPaths([ExtractFileDir(ParamStr(0)), 'profiles.json']);
  8.  
  9.   JSONData := ToJSON(FHeaderProfiles, FFileTypeProfiles);
  10.   try
  11.     fs := TFileStream.Create(ProfilesFile, fmCreate);
  12.     try
  13.       JSONText := JSONData.FormatJSON;
  14.       fs.WriteBuffer(JSONText[0], JSONText.Length);
  15.     finally
  16.       fs.Free;
  17.     end;
  18.   finally
  19.     JSONData.Free;
  20.   end;
As you can see, it creates a temporary TFileStream to write to the file. This requires an allocation which will be very short lived. This is how writing to a file looks in C++:
Code: C  [Select][+][-]
  1. std::ifstream fs{"file.txt"};
  2. fs << "Hello World!\n";
Note that this class is created on the stack, so no allocation is required.

So in Pascal you have a lot of small to medium sized allocations that are very short lived, something you typically avoid in C++. In C as a fully procedural language with manual memory management you typically use even less heap allocated memory (e.g. you often use stack buffers for strings because dynamic creation and destruction is annoying)

The C Memory manager is optimized for typical C and C++ programs, those are very different than typical Pascal Programs. So it's not really comparable.

I didn't know that. Is there even a single memory manager for C++ or does each of the major C++ compilers provide their own memory manager also?

Both, malloc and free are functions implemented in the LibC. You usually have one LibC provided by your OS (on Unix it's a requirement by the POSIX Spec), and this is also usually quite optimized code (often containing multiple versions for different functions optimized for specific processor types). That said, you can use different LibCs, even with different compilers. You can use the GLibC, UC-LibC or Musl LibC with you GCC or Clang, all having their own implementations for malloc and free.

Clang and GCC also ship the so called Address Sanatizer (ASAN), which amongst other features contains a custom memory manager similar to FPCs HeapTrc (but also has additional annotation functionalities, making it a much more powerful tool).

So it's not even up to the compiler really, it's up to the programmer to chose what LibC they want to use.

Additionally to that, C++ has an Allocator API as well as support for custom allocators for their New and Free keywords (equivalent to new and dispose in Pascal). This allows the programmer to use different memory managers in different situations.
For example I had once worked on a program where I would create a Tree consisting of alot of Nodes, which are dynamically allocated. I constructed the tree once, and then deleted all of Nodes at once when the tree was done.
So what I did was I created a LIFO Allocator, where I allocated a huge area of memory at once, with a pointer to the start, and when a new node was allocated, I would return that pointer and then move it by the size of the node. When I was done I would not free each node individually, but just free the whole block at once.
This gave me a massive improvement in performance on the construction and teardown of that tree, something a typical heap based memory manager would be to slow for.

And it's not just new and free, pretty much all classes in the STL (standard library) can be parametrized with a custom allocator. For example std::vector (basically a List type) just takes an allocator as template parameter, which will be used to allocate the list elements.

So long story short, in C++ there is not just one Memory Manager, you can find even multiple allocators used within a single project

 

TinyPortal © 2005-2018