0

How can I use Hoard Memory Manager in Delphi? I am looking for an alternative to FastMM, which is hopeless for serious multithreaded server applications. I looked at ScaleMM2 but it's not stable in 64 bit.

How can I statically link the Hoard Memory Manager. Since it comes with an OBJ file.

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144

3 Answers3

4

You cannot realistically hope to statically link Hoard because it is implemented in C++ and so needs a C++ runtime. You cannot expect to put a C++ runtime in your Delphi program.

So you need to build the Hoard memory manager in a DLL, for instance with Visual Studio. That DLL must export malloc, free and realloc. Do that with a .def file. Then you create a simple Delphi unit that links to the DLL and installs a memory manager based on these imported functions. Use my answer to the other question to guide you. As always, make the memory manager unit be the first unit in your .dpr file's uses list.

Do make sure you adhere to the license. You'll need to pay for a commercial license, or license your software under the GPL if I recall correctly.

FWIW, I use the malloc from the system C runtime in msvcrt.dll which scales better than FastMM.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • It depends massively on the application. IIRC, for my app, hoard was a little better (marginally) than msvcrt and FastMM significantly worse. But modern msvcrt (Vista+) is better than older versions (XP), IIRC. But other benchmarks reach different conclusions. In my case the best change I ever made was to stop using the heap wherever possible. – David Heffernan Jul 25 '14 at 12:30
  • Perhaps it could be. It might require a little effort. There may well be some initialization steps that would be require special treatment. And the Borland compiler is probably worse than the MS or Intel compilers in terms of perf. So static linking might be a bit tricky. And there's still the GPL issue. – David Heffernan Jul 25 '14 at 13:26
  • Well, Hoard is written in C, so C++ is not pertinent. Yes you could try to link MSVC produced .obj files. It's not the easiest task in the world. Especially for a complex piece of code. Ninja skills may be required. – David Heffernan Jul 25 '14 at 13:41
  • Actually I was wrong. Hoard is implemented in C++. So you'll need to stick to a DLL. – David Heffernan Jul 25 '14 at 13:53
  • We use C++ code from C code all time. It's simple. All that's needed is a C-compatible interface. Part of that means making the functions have C linkage, which you do by using `extern "C"`. That has the side effect of not using C++ name mangling. For example, see the end of [*libhoard.cpp*](https://github.com/emeryberger/Hoard/blob/master/src/source/libhoard.cpp). Linking it with *Delphi* isn't necessarily so easy because you'll have to provide links to the C and C++ standard libraries, too. C and C++ compilers do that automatically, but Delphi doesn't. – Rob Kennedy Jul 25 '14 at 16:18
  • Note that I've never used it. (Never even heard of it before today.) There are static compilation targets for the various Unix platforms, but the Hoard makefile builds only DLLs for Windows. Maybe it can't be linked statically on Windows. For building dynamically, follow the documented instructions: Run `nmake windows`. When the DLL is loaded, it patches functions exported by the MSVC runtime DLLs, so to use Hoard, you'd need to first be using those for memory management. See [David's code](http://stackoverflow.com/a/6072362/33732) for doing that. – Rob Kennedy Jul 25 '14 at 21:23
  • But maybe you *can* compile it for static linking. In that case, you could continue using [David's code](http://stackoverflow.com/a/6072362/33732) as a starting point, but instead of implementing the Delphi functions in terms of `malloc` and `free` from MSVCRT, you'd implement them using `xxmalloc` and `xxfree` from the Hoard object files. Note that `xxrealloc` is implemented in a different source file, *winwrapper.cpp* instead of *libhoard.cpp*. You could use that `xxrealloc`, or you could translate its implementation into Delphi. – Rob Kennedy Jul 25 '14 at 21:27
  • As far as I could tell from the code, the DLL doesn't actually export those functions. (Maybe it did back when FastCode tested it, but not anymore?) Rather, it expects you to already be using a DLL from MSVC, so it merely patches the functions from those DLLs instead. Use David's code for the MSVCRT memory functions, and then arrange to load the Hoard DLL, too. That's what *uselibhoard.cpp* is meant to do. – Rob Kennedy Jul 26 '14 at 12:01
  • I don't know. Try it and report back. There's only so much speculation I can do. You're the one with the compiler and the problem to solve. – Rob Kennedy Jul 26 '14 at 16:56
  • @user You just need to do what you have already been told. Nobody enjoys being told "doesn't work". No detail there. Build Hoard into a DLL. Export malloc, free and realloc. Use a .def file to do that. Use the msvcrtMM unit from my other answer but change the DLL name (and unit name). That's it. Building DLLs and exporting via def file is well documented on MSDN. – David Heffernan Jul 27 '14 at 07:27
4

As David mentioned, you need a .dll version. If you can't build it yourself, you can find pre-built versions. A quick search only turned up an older version, though.

André Mussche modified the FastCode MM Challenge to add Hoard in 2011. If you browse the source code, you will see examples of how it's used, including another precompiled copy of winhoard.dll. However, performance and memory usage weren't great in these tests.

Bruce McGee
  • 15,076
  • 6
  • 55
  • 70
  • As a counter to this, in my app, when I tested Hoard, there was a definite improvement on FastMM. So it seems to me that different applications may be better or worse suited to particular memory managers. In fact that's very much to be expected. For very high performance code it is not uncomment to design bespoke allocators that are designed for the specific environment which they serve. – David Heffernan Jul 25 '14 at 12:40
  • 1
    And FWIW, the source code you link to has this unit: `http://scalemm.googlecode.com/svn/trunk/Challenge/HoardMM.pas` which has this declaration `msvcrtDLL = 'libhoard.dll'` which makes me laugh. In fact that code, and this one (http://scalemm.googlecode.com/svn/trunk/Challenge/msvcrtMM.pas) are written by me it would seem! – David Heffernan Jul 25 '14 at 12:41
  • Yeah, it's fine. It's not exactly difficult to write it anyway. I expect I posted it on the Stack or one somebody's blog. *Update*: here it is: http://stackoverflow.com/questions/6072269/need-multi-threading-memory-manager – David Heffernan Jul 25 '14 at 12:52
  • I won't claim that all of the FastCode tests represent real world scenarios. If a better general benchmark exists, it might be more representative. – Bruce McGee Jul 25 '14 at 12:56
  • I suspect it's very hard to achieve that. Because different applications can have wildly different memory usage patterns and I believe it to be impossible to optimise for all reasonable usage patterns. I think that anyone looking to improve performance of their app would be best served by trying the available options in the setting of their app. Real world benchmark. And +1 btw. – David Heffernan Jul 25 '14 at 13:01
-2

Since everyone FAILED to provide a detailed solution. Here is a solution that actually works.

1: Open libhoard.cpp 2: Add the following lines to the code.

extern "C"{

__declspec(dllexport) void* scalable_malloc (size_t size)
{
    return malloc(size);
}

__declspec(dllexport) void* scalable_realloc (void* ptr, size_t size)
{
    return realloc(ptr, size);
}

__declspec(dllexport) void scalable_free (void* ptr)
{
    free(ptr);
}

}

3: Compile with nmake windows

4: Use it

unit hoard_mm;

interface

implementation

type
  size_t = Cardinal;

const
  hoardDLL = 'libhoard.dll';

function scalable_malloc(Size: size_t): Pointer; cdecl; external hoardDLL;
function scalable_realloc(P: Pointer; Size: size_t): Pointer; cdecl; external hoardDLL;
procedure scalable_free(P: Pointer); cdecl; external hoardDLL;

function GetMem(Size: NativeInt): Pointer; inline;
begin
  Result := scalable_malloc(size);
end;

function FreeMem(P: Pointer): Integer; inline;
begin
  scalable_free(P);
  Result := 0;
end;

function ReallocMem(P: Pointer; Size: NativeInt): Pointer; inline;
begin
  Result := scalable_realloc(P, Size);
end;

function AllocMem(Size: NativeInt): Pointer; inline;
begin
  Result := GetMem(Size);
  if Assigned(Result) then
  FillChar(Result^, Size, 0);
end;

function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean; inline;
begin
  Result := False;
end;

const
  MemoryManager: TMemoryManagerEx = (
    GetMem: GetMem;
    FreeMem: FreeMem;
    ReallocMem: ReallocMem;
    AllocMem: AllocMem;
    RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
    UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
  );

initialization
  SetMemoryManager(MemoryManager);

end.
  • You are so mean spirited. This is exactly what we told you to do over and over. It's even my code! And you've exported the functions badly. Do it with a .def file. And you didn't answer all of the question. Answers are meant to address the question that was asked. And you didn't format the code properly. You are really quite something. – David Heffernan Jul 27 '14 at 12:16
  • Read the question. Where did you ask for a detailed solution? And how different is your answer from mine? I assumed that you were capable of building a DLL and exporting functions. I didn't realise you needed told how to do that. Something that is well documented. And you did it poorly. Do it with a .def file so that you export the functions directly. You didn't answer all of the question. You did not format the code. Which is code that I wrote anyway! – David Heffernan Jul 27 '14 at 12:51
  • @DavidHeffernan Right. – user3863403 Jul 27 '14 at 13:14
  • There's not much point in us trying to help is there. You don't seem to want to listen to us. Why don't you just export malloc, realloc and free? And if you are going to publish other people's code, credit them with it otherwise it looks like you are claiming it as your own. – David Heffernan Jul 27 '14 at 15:00