This is happening with the latest version (0.9.73) and on the master branch.
erik On Thu, Dec 9, 2021 at 11:06 PM Evgeny Grin <k...@yandex.ru> wrote: > Hi Erik, > > It's hard to move forward without knowing exact MHD version used. > > Please share information about your MHD version. > > I suspect that your "Reply-To" header may confuse mailing list system. > Do not use "Reply-To" headers with mailing list. > > -- > Evgeny > > -------- Original Message -------- > From: Erik Smith <cruiserco...@gmail.com> > Sent: Friday, December 10, 2021, 03:29 UTC+3 > Subject: [libmicrohttpd] epoll and memory leaks > > > I've been able to reproduce this with a modified program from the > > examples to show the memory consumption I'm seeing. I'm using jemalloc > > to capture memory consumption and here's what it looks like for the > > program below when repeatedly hitting the endpoint: > > > > allocated: 120072, active: 163840, resident: 9150464 > > allocated: 150536, active: 196608, resident: 9228288 > > allocated: 181000, active: 229376, resident: 9306112 > > allocated: 211464, active: 262144, resident: 9383936 > > allocated: 211464, active: 262144, resident: 9383936 > > allocated: 241928, active: 294912, resident: 9461760 > > allocated: 272392, active: 327680, resident: 9539584 > > allocated: 272392, active: 327680, resident: 9539584 > > allocated: 302856, active: 360448, resident: 9617408 > > > > The delay in the handler and the use of ASAN tend to inflate the memory > > growth. The key factor here seems to be the use of the thread poll > > with either poll or epoll. Without the thread pool, there is no memory > > growth at all. The growth happens on low connection rates (manual > > refreshing in the browser). I haven't yet tried compiling MHD with > ASAN. > > > > I'm also not getting responses to my threads in email for some reason > > but I'm checking the archive. > > > > #include <cstring> > > #include <iostream> > > #include <jemalloc/jemalloc.h> > > #include <microhttpd.h> > > #include <sstream> > > #include <thread> > > > > static enum MHD_Result handler(void *, struct MHD_Connection *connection, > > const char *url, const char *method, > > const char *, const char *, size_t *, > > void **ptr) { > > static int aptr; > > > > if (&aptr != *ptr) { > > *ptr = &aptr; > > return MHD_YES; > > } > > *ptr = NULL; > > > > std::this_thread::sleep_for(std::chrono::milliseconds(40)); > > > > size_t sz = sizeof(size_t); > > uint64_t epoch = 1; > > mallctl("thread.tcache.flush", NULL, NULL, NULL, 0); > > mallctl("epoch", &epoch, &sz, &epoch, sz); > > > > std::size_t allocated, active, metadata, resident, mapped; > > mallctl("stats.allocated", &allocated, &sz, NULL, 0); > > mallctl("stats.active", &active, &sz, NULL, 0); > > mallctl("stats.resident", &resident, &sz, NULL, 0); > > > > std::stringstream s; > > s << "allocated: " << allocated << ", active: " << active > > << ", resident: " << resident << "\n"; > > auto msg = s.str(); > > > > std::cout << msg; > > > > struct MHD_Response *response = MHD_create_response_from_buffer( > > msg.size(), msg.data(), MHD_RESPMEM_MUST_COPY); > > MHD_Result ret = MHD_queue_response(connection, MHD_HTTP_OK, > response); > > MHD_destroy_response(response); > > return ret; > > } > > > > int main(int argc, char *argv[]) { > > struct MHD_Daemon *d; > > > > int port = argc > 1 ? atoi(argv[1]) : 10000; > > > > // epoll mode with thread pool > > unsigned int concurrency = std::thread::hardware_concurrency(); > > std::cout << "concurrency: " << concurrency << "\n"; > > > > d = MHD_start_daemon(MHD_USE_EPOLL_INTERNAL_THREAD | > > MHD_USE_ERROR_LOG, port, > > NULL, NULL, handler, NULL, > > MHD_OPTION_CONNECTION_TIMEOUT, > > (unsigned int)120, MHD_OPTION_STRICT_FOR_CLIENT, > > (int)1, > > MHD_OPTION_THREAD_POOL_SIZE, concurrency, NULL, > > MHD_OPTION_END); > > > > if (d == NULL) > > return 1; > > std::cout << "listening on port: " << port << "\n"; > > std::cout << "hit key to stop" > > << "\n"; > > > > // type a key to end > > (void)getc(stdin); > > MHD_stop_daemon(d); > > return 0; > > } > > > > > > Hi Erik, > > Which MHD version are you using? > > Some problems with externally added connections with epoll mode were > > fixed in v0.9.72. > > If you have any blocking calls, make sure that you use connection > > suspend/resume. Alternatively, you can you use thread-per-connection > > mode, this is less efficient, but simpler to implement. > > epoll mode does not have special memory allocation, connections are > > processed in the same way, like in other modes. MHD typically does > > not allocate memory during connection processing, except when new > > connection is started. > > Do you use postprosessor or authentication functions? MHD has some > > memory allocs in these functions. > > The issue is not connected with quoted comment definitely. It is > > just a bad wording. Actually nothing is leaked, but may be locked > > until end of sending of response. Moreover, MHD does not use memory > > pool in the way where such lock is possible. Memory pool is reset > > after each request-reply cycle. Memory pool size for each connection > > is fixed and cannot grow. > > A few suggestions: > > * make sure that you are using the latest MHD version (0.9.73 at the > > moment), * check whether you destroy responses and free all > > resources connected to responses, * if you are testing your code > > with ASAN, make sure that leak detector is enabled. You can build > > static MHD lib with ASAN and link it with our application compiled > > with ASAN, > > * use Valgrind or simpler tools like memstat or memprof. > > -- > > Wishes, > > Evgeny > > On 22.11.2021 22:56, Erik Smith wrote: > > /* Reallocate a block of memory obtained from the pool. > > * This is particularly efficient when growing or > > * shrinking the block that was last (re)allocated. > > * If the given block is not the most recently > > * (re)allocated block, the memory of the previous > > * allocation may be leaked until the pool is > > * destroyed or reset. */ > > Can anyone confirm whether this might be related? > > ASAN does not seem to detect any issues in our code presently (not > > sure about MHD) > > > > We have started to experiment with running MHD with epoll + thread > > pool as we do the FD limit in certain situations. We understand > > that there are caveats to this given that we have some > > blocking database calls. This seems to get us past the FD limit > > errors and the performance is similar. However, we are running > > into growing memory consumption in our server over time > > running epoll+threads that require a restart frequently. This does > > not seem to occur with just epoll (without the thread pool). We > > are running jemalloc, but it does not seem to be related to the leak > > when it is disabled. There is the following comment in the MHD code > > for the MHD_pool_reallocate function that might be connected to this > > issue: > > >