Core: Increase maximum number of open file handles

On Windows and macOS, the default maximum number of stdio file handles
is 512 and 256 respectively. On Linux it's usually some very high
number. This increases that limit on startup to 8192, to better handle
some production files and have more uniform limits across platforms.
This is commonly done in VFX software.

Some code in Blender keeps file handles open for a long time,
particularly the Cycles texture cache and Alembic cache file datablocks.
This helps improve performance when reading tiles or frames on demand,
without having to reopen the file each time.

Cycles limits itself to 128 file handles, but there is no limit on cache
file datablocks. The production file in #160383 has 480 open file
handles for Alembic, so it was already near the limit on Windows, and
then a few more pushed it over.

By increasing the limit, at a minimum all production files that worked
before should continue to work when enabling the texture cache.
Improving the cache file datablock to use fewer handles is left for
another time.

Fix #160383: Cycles texture missing images in production file

Pull Request: https://projects.blender.org/blender/blender/pulls/160488
This commit is contained in:
Brecht Van Lommel 2026-06-23 12:29:51 +02:00 • committed by Brecht Van Lommel
parent 8074e1f01e
commit 7b6485f549
7 changed files with 80 additions and 0 deletions

View file

@ -16,6 +16,7 @@
#include "util/path.h"
#include "util/progress.h"
#include "util/string.h"
#include "util/system.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
# include "util/time.h"
# include "util/transform.h"
@ -541,6 +542,7 @@ int main(const int argc, const char **argv)
{
log_init(nullptr);
path_init();
system_max_open_files_ensure();
options_parse(argc, argv);
#ifdef WITH_CYCLES_STANDALONE_GUI

View file

@ -3,8 +3,12 @@
* SPDX-License-Identifier: Apache-2.0 */
#include "util/system.h"
#include "util/log.h"
#include "util/string.h"
#include <algorithm>
#include <cstring>
#ifdef _WIN32
# include <cstdio>
# if (!defined(FREE_WINDOWS))
@ -279,4 +283,29 @@ size_t system_max_open_files()
#endif
}
void system_max_open_files_ensure()
{
/* The Windows maximum is 8192 open files. */
constexpr int max_open_files = 8192;
bool ok = true;
#if defined(_WIN32)
if (_getmaxstdio() < max_open_files) {
ok = _setmaxstdio(max_open_files) == max_open_files;
}
#else
struct rlimit limit = {};
ok = getrlimit(RLIMIT_NOFILE, &limit) == 0;
if (ok && limit.rlim_cur < rlim_t(max_open_files)) {
limit.rlim_cur = std::min(rlim_t(max_open_files), limit.rlim_max);
ok = setrlimit(RLIMIT_NOFILE, &limit) == 0;
}
#endif
if (!ok) {
LOG_DEBUG << "Failed to ensure max open files is at least " << max_open_files << ": "
<< strerror(errno);
}
}
CCL_NAMESPACE_END

View file

@ -26,4 +26,8 @@ uint64_t system_self_process_id();
size_t system_max_open_files();
/* Ensure the process can open many files simultaneously.
* This should be called once on application startup, as it is not thread safe. */
void system_max_open_files_ensure();
CCL_NAMESPACE_END

View file

@ -40,6 +40,12 @@ size_t BLI_system_memory_max_in_megabytes();
/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */
int BLI_system_memory_max_in_megabytes_int();
/**
* Ensure the process can open many files simultaneously.
* This should be called once on application startup, as it is not thread safe.
*/
void BLI_system_max_open_files_ensure();
/* For `getpid`. */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>

View file

@ -426,6 +426,7 @@ set(LIB
PRIVATE bf::extern::xxhash
bf_intern_eigen
PRIVATE bf::intern::guardedalloc
PRIVATE bf::intern::clog
PRIVATE bf::extern::wcwidth
PRIVATE bf::intern::atomic
PUBLIC bf::intern::profile

View file

@ -6,9 +6,13 @@
* \ingroup bli
*/
#include <algorithm>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "CLG_log.h"
#include "BLI_math_base.h"
#include "BLI_mutex.hh"
@ -24,11 +28,14 @@
# if defined(HAVE_EXECINFO_H)
# include <execinfo.h>
# endif
# include <sys/resource.h>
# include <unistd.h>
#endif
namespace blender {
static CLG_LogRef LOG = {"system"};
int BLI_cpu_support_sse2()
{
#if defined(__x86_64__) || defined(_M_X64)
@ -215,4 +222,31 @@ int BLI_system_memory_max_in_megabytes_int()
return int(min_zz(limit_megabytes, size_t(INT_MAX)));
}
void BLI_system_max_open_files_ensure()
{
/* The Windows maximum is documented as 8192. */
constexpr int max_open_files = 8192;
bool ok = true;
#if defined(WIN32)
if (_getmaxstdio() < max_open_files) {
ok = _setmaxstdio(max_open_files) == max_open_files;
}
#else
struct rlimit limit;
ok = getrlimit(RLIMIT_NOFILE + 120937, &limit) == 0;
if (ok && limit.rlim_cur < rlim_t(max_open_files)) {
limit.rlim_cur = std::min(rlim_t(max_open_files), limit.rlim_max);
ok = setrlimit(RLIMIT_NOFILE, &limit) == 0;
}
#endif
if (!ok) {
CLOG_DEBUG(&LOG,
"Failed to ensure max open files is at least %d: %s",
max_open_files,
strerror(errno));
}
}
} // namespace blender

View file

@ -553,6 +553,10 @@ int main(int argc,
CCL_implicit_sharing_init();
#endif
/* Set max open files to better handle production files that may use many
* open geometry or texture cache file handles. After logging since it's used .*/
BLI_system_max_open_files_ensure();
/* Must be initialized after #BKE_appdir_init to account for color-management paths. */
IMB_init();
/* Keep after #ARG_PASS_SETTINGS since debug flags are checked. */