Live data from Hacker News

Memory – Part 4: Intersec’s custom allocators

techtalk.intersec.com

31–40 of 62 posts

Re: Memory – Part 4: Intersec’s custom allocators

#31
Not about heap allocators but I followed the "About" link to this text:

> At Intersec, technology matters…Because it’s the core of our business, we aim to provide our clients with the most innovative and disruptive technological solutions. We do not believe in the benefits of reusing and staking external software bricks when developing our products. Our software is built in C language under Linux, with PHP/JavaScript for the web interfaces and it is continuously improved ...

So now I'm wondering whether PHP is actually perceived as being hard-core?

Also, how would one stake a brick?

Re: Memory – Part 4: Intersec’s custom allocators

#32
post #18

Earlier quoted context omitted.

There is an extended version of C, which is has this feature and is nearly as widely ported as C. They aptly named it C++.

Then "they" later discovered the name was no longer apt and it should have been called ++C.

C++ is the correct name, you write a few thousand lines C code and then write class LargeObject in the first line. So C++.

Re: Memory – Part 4: Intersec’s custom allocators

#33

Not about heap allocators but I followed the "About" link to this text: > At Intersec, technology matters…Because it’s the core of our business, we aim to provide our clients with the most innovative and disruptive technological solutions. We do not believe in the benefits of reusing and staking external software bricks when developing our products. Our software is built in C language under Linux, with PHP/JavaScript…

C+PHP+Ajax(+SCGI or FastCGI) is my go-to when I want to create essentially a custom webserver but don't actually want to reinvent an entire http daemon from scratch. The PHP is used to simplify routine annoying tasks, while letting the custom server do the fun stuff.

Re: Memory – Part 4: Intersec’s custom allocators

#34
post #29
post #27

Earlier quoted context omitted.

Contra "exDM69", there's nothing unreasonable or "unrealistic" about allocating 8 bytes at a time; it's in fact extremely convenient to be able to do that. I think it's telling that someone would call that workload unrealistic; it indicates to me that they've never even really considered alternatives to malloc. It's a little like those C programmers who try to use 256 byte static arrays for all their strings because…

Well, personally, if I'm using C, it's typically for a very narrowly defined, performance-sensitive problem. Both times I've done this in the last couple years, I found myself doing a couple big mallocs at the start and then running some tight loops over that memory with no further mallocs -- for use cases with more allocation, I'll just use whatever other language is more convenient, preferably one with a GC. But if…

That is similar to the signal processing application I worked on a couple years ago. It was a real-time application with fixed sizes at each point in the algorithm, so we knew maximum memory usage at initialization. Thus, we allocated all memory up-front and continuously reused the buffers until we were shut down. Under the operational architecture we were moving to when I left, our application never actually called malloc at all; the control program that ran the signal processor and which started us malloced massive segments of memory on each machine and gave it to us, which we then "allocated" to our own buffers.

Re: Memory – Part 4: Intersec’s custom allocators

#35
post #18

Earlier quoted context omitted.

There is an extended version of C, which is has this feature and is nearly as widely ported as C. They aptly named it C++.

C++ has an IMHO worse version of this feature, that requires a custom type, and that only allows a single function to be called for that type. This is more like Go's defer, and is far more appropriate for my use cases.

I haven't written much C++ in quite a few years - mostly do Ruby these days, so I'm sure I'm making some terribly embarrassing faux pas or other with the example below. But you don't need more than the C++ functionality to compose your own variations if you want more flexibility.

For example:

  #include 
  #include 

  class Scope {

  private:
    typedef std::vector FV;
    FV fv;
  public:
    void on_return(void (* f)()) {
      fv.push_back(f);
    }

    ~Scope() {
      for (FV::iterator it = fv.begin(); it != fv.end(); ++it) {
        (*it)();
      }
    }
  };

  void foo() {
    std::cout 
With C++11 lambda syntax you can do quite a bit better.

Expanding that into something providing at least most of what Go's "defer" does shouldn't be too hard.

Re: Memory – Part 4: Intersec’s custom allocators

#36

Not about heap allocators but I followed the "About" link to this text: > At Intersec, technology matters…Because it’s the core of our business, we aim to provide our clients with the most innovative and disruptive technological solutions. We do not believe in the benefits of reusing and staking external software bricks when developing our products. Our software is built in C language under Linux, with PHP/JavaScript…

PHP can be thought of as ``configuration + templating language for your C application'', with the C application being both the http server, and stock and your custom PHP plugins.

Yes, the whole stack can get hardcore, as long as you don't force PHP to do what other parts of the stack (SQL, JS) excel at, if you end up processing large datasets in short time :^)

Re: Memory – Part 4: Intersec’s custom allocators

#37
post #10

The fact that returning memory to the Kernel is hard is supported by the circumstance, that most allocators will use brk/sbrk to resize the data segment of the executing process to allocate memory, at least if they shall allocate few memory. The other fact, that allocators have to lock global data structures is also not true. Most modern operating systems supports thread-local storage and therefore you don't need loc…

> Most modern operating systems supports thread-local storage and therefore you don't need locking because you can keep much per-threads allocators

The article explicitly points this out, and points out the problem with it: It means wasting memory on per-thread pools, and the more threads you use, the larger the pools needs to be if you want to prevent contention, compounding the problem.

> because most well-written software will allocate large chunks of memory.

1. Most software is not well written.

2. Most large pieces well written pieces of software that allocates only large chunks of memory has some custom allocator of some sort (or horrible abuses of arrays) embedded somewhere to work around exactly the problems noted in the article. In many cases people end up wasting time writing the same types of specialised allocators over and over.

I've seen plenty of large C and C++ apps that'd have benefitted greatly from a simple arena allocator for example... And I have also seen countless of implementations of arena allocators and various pool allocators and tons of other variations.

In other words: These things do exist. They're common, to the point where they're often covered in books on C/C++. Especially for C++ where there is specific built in (though weak) support for custom allocators.

Re: Memory – Part 4: Intersec’s custom allocators

#38
post #28
post #4

It should be obvious that a lot of 8 byte mallocs will give bad performance and horrible memory use. This article and in particular the benchmarks in it would be a lot more informative if the test case was more realistic. Please add at least 32 or 64 bytes of payload to the linked list structure and re-run the benchmarks. Even that is a very small allocation block, but is on the lower end of realistic allocation size…

The post starts out by explaining that malloc is a generic allocator and is thus less performant. Your comment seems premised on the idea that the author is suggesting a replacement for malloc in all its use cases, which he pointedly is not doing. Instead of him re-running his benchmarks, you should give the post a closer re-read.

I hate to go meta, but that last sentence in your post could have been omitted with no detriment to the post's message and great improvement to the tone.

Re: Memory – Part 4: Intersec’s custom allocators

#39
post #35

Earlier quoted context omitted.

C++ has an IMHO worse version of this feature, that requires a custom type, and that only allows a single function to be called for that type. This is more like Go's defer, and is far more appropriate for my use cases.

I haven't written much C++ in quite a few years - mostly do Ruby these days, so I'm sure I'm making some terribly embarrassing faux pas or other with the example below. But you don't need more than the C++ functionality to compose your own variations if you want more flexibility. For example: #include #include class Scope { private: typedef std::vector FV; FV fv; public: void on_return(void (* f)()) { fv.push_back(f)…

Good idea, this definitely accomplishes the same functionality, but it's done at runtime, rather than the compiler knowing all the functions at compile time. Perhaps a minor difference for most cases, though...

I would still prefer a C extension... Perhaps I should just use Go these days, though ironically all these memory allocation policies are useless in a GC language.

Re: Memory – Part 4: Intersec’s custom allocators

#40
post #10

The fact that returning memory to the Kernel is hard is supported by the circumstance, that most allocators will use brk/sbrk to resize the data segment of the executing process to allocate memory, at least if they shall allocate few memory. The other fact, that allocators have to lock global data structures is also not true. Most modern operating systems supports thread-local storage and therefore you don't need loc…

> (...) that most allocators will use brk/sbrk to resize the data segment of the executing process to allocate memory, at least if they shall allocate few memory.

The other commonly used backend for malloc() is mmap() without underlying file:

  void *chunk = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, -1, 0);
Handy both when allocating large chunks of memory and for allocating pools for smaller suballocations. Has the additional benefit of being zeroed-out at low cost (or no cost at all -- for example via hardware DMA), and also playing nice on systems with constrained / fragmented address space, as kernel is free to allocate at any address visible from userspace.
Post reply on HN