mirror of
https://github.com/minetest/minetest.git
synced 2024-12-24 15:12:23 +01:00
Call malloc_trim() regularly to improve deallocation behavior (#14707)
This commit is contained in:
parent
08485f6781
commit
71893807b3
@ -176,6 +176,32 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Calculate size of vertices and indices in memory
|
||||
virtual size_t getSize() const
|
||||
{
|
||||
size_t ret = 0;
|
||||
switch (getVertexType()) {
|
||||
case video::EVT_STANDARD:
|
||||
ret += sizeof(video::S3DVertex) * getVertexCount();
|
||||
break;
|
||||
case video::EVT_2TCOORDS:
|
||||
ret += sizeof(video::S3DVertex2TCoords) * getVertexCount();
|
||||
break;
|
||||
case video::EVT_TANGENTS:
|
||||
ret += sizeof(video::S3DVertexTangents) * getVertexCount();
|
||||
break;
|
||||
}
|
||||
switch (getIndexType()) {
|
||||
case video::EIT_16BIT:
|
||||
ret += sizeof(u16) * getIndexCount();
|
||||
break;
|
||||
case video::EIT_32BIT:
|
||||
ret += sizeof(u32) * getIndexCount();
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
@ -351,6 +351,12 @@ endif()
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
|
||||
|
||||
if(UNIX)
|
||||
check_symbol_exists(malloc_trim "malloc.h" HAVE_MALLOC_TRIM)
|
||||
else()
|
||||
set(HAVE_MALLOC_TRIM FALSE)
|
||||
endif()
|
||||
|
||||
check_include_files(endian.h HAVE_ENDIAN_H)
|
||||
|
||||
configure_file(
|
||||
|
@ -800,11 +800,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
||||
|
||||
MapBlockMesh::~MapBlockMesh()
|
||||
{
|
||||
size_t sz = 0;
|
||||
for (scene::IMesh *m : m_mesh) {
|
||||
for (u32 i = 0; i < m->getMeshBufferCount(); i++)
|
||||
sz += m->getMeshBuffer(i)->getSize();
|
||||
m->drop();
|
||||
}
|
||||
for (MinimapMapblock *block : m_minimap_mapblocks)
|
||||
delete block;
|
||||
|
||||
porting::TrackFreedMemory(sz);
|
||||
}
|
||||
|
||||
bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
||||
|
@ -31,6 +31,7 @@
|
||||
#cmakedefine01 USE_REDIS
|
||||
#cmakedefine01 HAVE_ENDIAN_H
|
||||
#cmakedefine01 HAVE_STRLCPY
|
||||
#cmakedefine01 HAVE_MALLOC_TRIM
|
||||
#cmakedefine01 CURSES_HAVE_CURSES_H
|
||||
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
||||
#cmakedefine01 CURSES_HAVE_NCURSES_NCURSES_H
|
||||
|
@ -85,6 +85,7 @@ MapBlock::~MapBlock()
|
||||
#endif
|
||||
|
||||
delete[] data;
|
||||
porting::TrackFreedMemory(sizeof(MapNode) * nodecount);
|
||||
}
|
||||
|
||||
bool MapBlock::onObjectsActivation()
|
||||
|
@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <typeinfo>
|
||||
#include "mg_schematic.h"
|
||||
#include "server.h"
|
||||
#include "mapgen.h"
|
||||
@ -32,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "serialization.h"
|
||||
#include "filesys.h"
|
||||
#include "voxelalgorithms.h"
|
||||
#include "porting.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -80,6 +80,8 @@ Schematic::~Schematic()
|
||||
{
|
||||
delete []schemdata;
|
||||
delete []slice_probs;
|
||||
u32 nodecount = size.X * size.Y * size.Z;
|
||||
porting::TrackFreedMemory(nodecount * sizeof(MapNode));
|
||||
}
|
||||
|
||||
ObjDef *Schematic::clone() const
|
||||
|
@ -63,7 +63,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <FindDirectory.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_MALLOC_TRIM
|
||||
// glibc-only pretty much
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "filesys.h"
|
||||
#include "log.h"
|
||||
@ -72,6 +76,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <signal.h>
|
||||
#include <atomic>
|
||||
|
||||
#if !defined(SERVER) && defined(_WIN32)
|
||||
// On Windows export some driver-specific variables to encourage Minetest to be
|
||||
@ -903,4 +908,37 @@ double perf_freq = get_perf_freq();
|
||||
|
||||
#endif
|
||||
|
||||
#if HAVE_MALLOC_TRIM
|
||||
|
||||
/*
|
||||
* On Linux/glibc we found that after deallocating bigger chunks of data (esp. MapBlocks)
|
||||
* the memory would not be given back to the OS and would stay at peak usage.
|
||||
* This appears to be a combination of unfortunate allocation order/fragmentation
|
||||
* and the fact that glibc does not call madvise(MADV_DONTNEED) on its own.
|
||||
* Some other allocators were also affected, jemalloc and musl libc were not.
|
||||
* read more: <https://forum.minetest.net/viewtopic.php?t=30509>
|
||||
*
|
||||
* As a workaround we track freed memory coarsely and call malloc_trim() once a
|
||||
* certain amount is reached.
|
||||
*/
|
||||
|
||||
static std::atomic<size_t> memory_freed;
|
||||
|
||||
constexpr size_t MEMORY_TRIM_THRESHOLD = 128 * 1024 * 1024;
|
||||
|
||||
void TrackFreedMemory(size_t amount)
|
||||
{
|
||||
constexpr auto MO = std::memory_order_relaxed;
|
||||
memory_freed.fetch_add(amount, MO);
|
||||
if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) {
|
||||
// Synchronize call
|
||||
if (memory_freed.exchange(0, MO) < MEMORY_TRIM_THRESHOLD)
|
||||
return;
|
||||
// Leave some headroom for future allocations
|
||||
malloc_trim(1 * 1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace porting
|
||||
|
@ -290,6 +290,17 @@ void osSpecificInit();
|
||||
// This attaches to the parents process console, or creates a new one if it doesnt exist.
|
||||
void attachOrCreateConsole();
|
||||
|
||||
/**
|
||||
* Call this after freeing bigger blocks of memory. Used on some platforms to
|
||||
* properly give memory back to the OS.
|
||||
* @param amount Number of bytes freed
|
||||
*/
|
||||
#if HAVE_MALLOC_TRIM
|
||||
void TrackFreedMemory(size_t amount);
|
||||
#else
|
||||
inline void TrackFreedMemory(size_t amount) { (void)amount; }
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Quotes an argument for use in a CreateProcess() commandline (not cmd.exe!!)
|
||||
std::string QuoteArgv(const std::string &arg);
|
||||
@ -298,6 +309,7 @@ std::string QuoteArgv(const std::string &arg);
|
||||
std::string ConvertError(DWORD error_code);
|
||||
#endif
|
||||
|
||||
// snprintf wrapper
|
||||
int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "nodedef.h"
|
||||
#include "util/directiontables.h"
|
||||
#include "util/timetaker.h"
|
||||
#include "porting.h"
|
||||
#include <cstring> // memcpy, memset
|
||||
|
||||
/*
|
||||
@ -40,12 +41,15 @@ VoxelManipulator::~VoxelManipulator()
|
||||
|
||||
void VoxelManipulator::clear()
|
||||
{
|
||||
// Reset area to volume=0
|
||||
m_area = VoxelArea();
|
||||
// Reset area to empty volume
|
||||
VoxelArea old;
|
||||
std::swap(m_area, old);
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
delete[] m_flags;
|
||||
m_flags = nullptr;
|
||||
|
||||
porting::TrackFreedMemory((sizeof(*m_data) + sizeof(*m_flags)) * old.getVolume());
|
||||
}
|
||||
|
||||
void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
|
||||
|
Loading…
Reference in New Issue
Block a user