mirror of
https://github.com/minetest/minetest.git
synced 2025-01-12 08:17:31 +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;
|
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
|
} // end namespace scene
|
||||||
|
@ -351,6 +351,12 @@ endif()
|
|||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
|
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)
|
check_include_files(endian.h HAVE_ENDIAN_H)
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
|
@ -800,11 +800,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||||||
|
|
||||||
MapBlockMesh::~MapBlockMesh()
|
MapBlockMesh::~MapBlockMesh()
|
||||||
{
|
{
|
||||||
|
size_t sz = 0;
|
||||||
for (scene::IMesh *m : m_mesh) {
|
for (scene::IMesh *m : m_mesh) {
|
||||||
|
for (u32 i = 0; i < m->getMeshBufferCount(); i++)
|
||||||
|
sz += m->getMeshBuffer(i)->getSize();
|
||||||
m->drop();
|
m->drop();
|
||||||
}
|
}
|
||||||
for (MinimapMapblock *block : m_minimap_mapblocks)
|
for (MinimapMapblock *block : m_minimap_mapblocks)
|
||||||
delete block;
|
delete block;
|
||||||
|
|
||||||
|
porting::TrackFreedMemory(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#cmakedefine01 USE_REDIS
|
#cmakedefine01 USE_REDIS
|
||||||
#cmakedefine01 HAVE_ENDIAN_H
|
#cmakedefine01 HAVE_ENDIAN_H
|
||||||
#cmakedefine01 HAVE_STRLCPY
|
#cmakedefine01 HAVE_STRLCPY
|
||||||
|
#cmakedefine01 HAVE_MALLOC_TRIM
|
||||||
#cmakedefine01 CURSES_HAVE_CURSES_H
|
#cmakedefine01 CURSES_HAVE_CURSES_H
|
||||||
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
||||||
#cmakedefine01 CURSES_HAVE_NCURSES_NCURSES_H
|
#cmakedefine01 CURSES_HAVE_NCURSES_NCURSES_H
|
||||||
|
@ -85,6 +85,7 @@ MapBlock::~MapBlock()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
delete[] data;
|
delete[] data;
|
||||||
|
porting::TrackFreedMemory(sizeof(MapNode) * nodecount);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapBlock::onObjectsActivation()
|
bool MapBlock::onObjectsActivation()
|
||||||
|
@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <typeinfo>
|
|
||||||
#include "mg_schematic.h"
|
#include "mg_schematic.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "mapgen.h"
|
#include "mapgen.h"
|
||||||
@ -32,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "voxelalgorithms.h"
|
#include "voxelalgorithms.h"
|
||||||
|
#include "porting.h"
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -80,6 +80,8 @@ Schematic::~Schematic()
|
|||||||
{
|
{
|
||||||
delete []schemdata;
|
delete []schemdata;
|
||||||
delete []slice_probs;
|
delete []slice_probs;
|
||||||
|
u32 nodecount = size.X * size.Y * size.Z;
|
||||||
|
porting::TrackFreedMemory(nodecount * sizeof(MapNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjDef *Schematic::clone() const
|
ObjDef *Schematic::clone() const
|
||||||
|
@ -63,7 +63,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <FindDirectory.h>
|
#include <FindDirectory.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#if HAVE_MALLOC_TRIM
|
||||||
|
// glibc-only pretty much
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -72,6 +76,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#if !defined(SERVER) && defined(_WIN32)
|
#if !defined(SERVER) && defined(_WIN32)
|
||||||
// On Windows export some driver-specific variables to encourage Minetest to be
|
// On Windows export some driver-specific variables to encourage Minetest to be
|
||||||
@ -903,4 +908,37 @@ double perf_freq = get_perf_freq();
|
|||||||
|
|
||||||
#endif
|
#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
|
} //namespace porting
|
||||||
|
@ -290,6 +290,17 @@ void osSpecificInit();
|
|||||||
// This attaches to the parents process console, or creates a new one if it doesnt exist.
|
// This attaches to the parents process console, or creates a new one if it doesnt exist.
|
||||||
void attachOrCreateConsole();
|
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
|
#ifdef _WIN32
|
||||||
// Quotes an argument for use in a CreateProcess() commandline (not cmd.exe!!)
|
// Quotes an argument for use in a CreateProcess() commandline (not cmd.exe!!)
|
||||||
std::string QuoteArgv(const std::string &arg);
|
std::string QuoteArgv(const std::string &arg);
|
||||||
@ -298,6 +309,7 @@ std::string QuoteArgv(const std::string &arg);
|
|||||||
std::string ConvertError(DWORD error_code);
|
std::string ConvertError(DWORD error_code);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// snprintf wrapper
|
||||||
int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...);
|
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 "nodedef.h"
|
||||||
#include "util/directiontables.h"
|
#include "util/directiontables.h"
|
||||||
#include "util/timetaker.h"
|
#include "util/timetaker.h"
|
||||||
|
#include "porting.h"
|
||||||
#include <cstring> // memcpy, memset
|
#include <cstring> // memcpy, memset
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -40,12 +41,15 @@ VoxelManipulator::~VoxelManipulator()
|
|||||||
|
|
||||||
void VoxelManipulator::clear()
|
void VoxelManipulator::clear()
|
||||||
{
|
{
|
||||||
// Reset area to volume=0
|
// Reset area to empty volume
|
||||||
m_area = VoxelArea();
|
VoxelArea old;
|
||||||
|
std::swap(m_area, old);
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_data = nullptr;
|
m_data = nullptr;
|
||||||
delete[] m_flags;
|
delete[] m_flags;
|
||||||
m_flags = nullptr;
|
m_flags = nullptr;
|
||||||
|
|
||||||
|
porting::TrackFreedMemory((sizeof(*m_data) + sizeof(*m_flags)) * old.getVolume());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
|
void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
|
||||||
|
Loading…
Reference in New Issue
Block a user