This commit is contained in:
Alexander Aleksandrovič Klimov 2026-02-03 15:23:57 +01:00 committed by GitHub
commit 1441ca9735
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 148 additions and 0 deletions

View file

@ -371,6 +371,7 @@ check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS)
check_function_exists(pipe2 HAVE_PIPE2)
check_function_exists(nice HAVE_NICE)
check_function_exists(malloc_info HAVE_MALLOC_INFO)
check_function_exists(malloc_trim HAVE_MALLOC_TRIM)
check_function_exists(pthread_set_name_np HAVE_PTHREAD_SET_NAME_NP)
check_function_exists(pthread_setname_np HAVE_PTHREAD_SETNAME_NP)
check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR)

View file

@ -9,6 +9,7 @@
#cmakedefine HAVE_CXXABI_H
#cmakedefine HAVE_NICE
#cmakedefine HAVE_MALLOC_INFO
#cmakedefine HAVE_MALLOC_TRIM
#cmakedefine HAVE_PTHREAD_SET_NAME_NP
#cmakedefine HAVE_PTHREAD_SETNAME_NP
#cmakedefine HAVE_EDITLINE

View file

@ -2594,6 +2594,40 @@ but the raw XML output from `malloc_info(3)`. See also the
</malloc>
```
### Memory Usage Reduction <a id="icinga2-api-memory-trim"></a>
The GNU libc function `malloc_trim(3)` attempts to release free memory
from the main heap arena of Icinga 2 itself. You can call it directly
by sending a `POST` request to the URL endpoint `/v1/debug/malloc_trim`.
The following parameters may be specified
(either as URL parameters or in a JSON-encoded message body):
Parameter | Type | Description
----------|--------|-------------
pad | Number | **Optional.** How many heap bytes to preserve, so the next `malloc(3)` call doesn't need to re-allocate memory again via `sbrk(2)`. Defaults to 0.
The [API permission](12-icinga2-api.md#icinga2-api-permissions) `debug` is required.
Example:
```bash
curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \
-X POST 'https://localhost:5665/v1/debug/malloc_trim?pad=1'
```
```json
{
"results": [
{
"code": 200.0,
"malloc_trim": 1.0,
"status": "Some memory was released back to the system."
}
]
}
```
## API Clients <a id="icinga2-api-clients"></a>
After its initial release in 2015, community members

View file

@ -34,6 +34,7 @@ set(remote_SOURCES
jsonrpc.cpp jsonrpc.hpp
jsonrpcconnection.cpp jsonrpcconnection.hpp jsonrpcconnection-heartbeat.cpp jsonrpcconnection-pki.cpp
mallocinfohandler.cpp mallocinfohandler.hpp
malloctrimhandler.cpp malloctrimhandler.hpp
messageorigin.cpp messageorigin.hpp
modifyobjecthandler.cpp modifyobjecthandler.hpp
objectqueryhandler.cpp objectqueryhandler.hpp

View file

@ -0,0 +1,84 @@
/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */
#include "remote/filterutility.hpp"
#include "remote/httputility.hpp"
#include "remote/malloctrimhandler.hpp"
#include <boost/lexical_cast.hpp>
#include <cstddef>
#ifdef HAVE_MALLOC_TRIM
# include <malloc.h>
#endif /* HAVE_MALLOC_TRIM */
using namespace icinga;
REGISTER_URLHANDLER("/v1/debug/malloc_trim", MallocTrimHandler);
bool MallocTrimHandler::HandleRequest(
AsioTlsStream&,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
const Dictionary::Ptr& params,
boost::asio::yield_context&,
HttpServerConnection&
)
{
namespace http = boost::beast::http;
if (url->GetPath().size() != 3) {
return false;
}
if (request.method() != http::verb::post) {
return false;
}
auto rawPad (HttpUtility::GetLastParameter(params, "pad"));
size_t pad = 0;
if (rawPad.GetType() != ValueEmpty) {
try {
pad = boost::lexical_cast<size_t>(rawPad);
} catch (const std::exception&) {
HttpUtility::SendJsonError(response, params, 400,
"Invalid 'pad' specified. An integer [0," BOOST_PP_STRINGIZE(SIZE_MAX) "] is required.");
return true;
}
}
FilterUtility::CheckPermission(user, "debug");
#ifndef HAVE_MALLOC_TRIM
HttpUtility::SendJsonError(response, params, 501, "malloc_trim(3) not available.");
#else /* HAVE_MALLOC_TRIM */
Dictionary::Ptr result1;
auto ret (malloc_trim(pad));
if (ret) {
result1 = new Dictionary({
{ "code", 200 },
{ "malloc_trim", ret },
{ "status", "Some memory was released back to the system." }
});
} else {
result1 = new Dictionary({
{ "code", 503 },
{ "malloc_trim", ret },
{ "status", "It was not possible to release any memory." }
});
response.result(http::status::service_unavailable);
}
Dictionary::Ptr result = new Dictionary({
{ "results", new Array({ result1 }) }
});
HttpUtility::SendJsonBody(response, params, result);
#endif /* HAVE_MALLOC_TRIM */
return true;
}

View file

@ -0,0 +1,27 @@
/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */
#pragma once
#include "remote/httphandler.hpp"
namespace icinga
{
class MallocTrimHandler final : public HttpHandler
{
public:
DECLARE_PTR_TYPEDEFS(MallocTrimHandler);
bool HandleRequest(
AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
const Dictionary::Ptr& params,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
};
}