diff --git a/ide/vs2019/mimalloc-override-test.vcxproj b/ide/vs2019/mimalloc-override-test.vcxproj
new file mode 100644
index 00000000..d75a67e1
--- /dev/null
+++ b/ide/vs2019/mimalloc-override-test.vcxproj
@@ -0,0 +1,165 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {FEF7868F-750E-4C21-A04D-22707CC66879}
+ mimalloc-override-test
+ 10.0
+ mimalloc-override-test
+
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+ MultiThreadedDebugDLL
+
+
+ Console
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+ MultiThreadedDebugDLL
+
+
+ Console
+
+
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ false
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ _MBCS;%(PreprocessorDefinitions);NDEBUG
+ MultiThreadedDLL
+
+
+ true
+ true
+ Console
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ _MBCS;%(PreprocessorDefinitions);NDEBUG
+ MultiThreadedDLL
+
+
+ true
+ true
+ Console
+
+
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+ {abb5eae7-b3e6-432e-b636-333449892ea7}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj
new file mode 100644
index 00000000..1f3b7ee2
--- /dev/null
+++ b/ide/vs2019/mimalloc-override.vcxproj
@@ -0,0 +1,243 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}
+ mimalloc-override
+ 10.0
+ mimalloc-override
+
+
+
+ DynamicLibrary
+ true
+ v142
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+
+
+ DynamicLibrary
+ true
+ v142
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .dll
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .dll
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .dll
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .dll
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ../../include
+ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);
+ MultiThreadedDebugDLL
+ false
+
+
+
+
+
+
+
+
+
+
+ DllEntry
+ kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ../../include
+ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);
+ MultiThreadedDebugDLL
+ false
+
+
+
+
+
+
+
+
+
+
+ DllEntry
+ kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ../../include
+ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);NDEBUG
+ AssemblyAndSourceCode
+ $(IntDir)
+ false
+ MultiThreadedDLL
+
+
+ true
+ true
+ DllEntry
+ kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ../../include
+ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);NDEBUG
+ AssemblyAndSourceCode
+ $(IntDir)
+ false
+ MultiThreadedDLL
+
+
+ true
+ true
+ DllEntry
+ kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj
new file mode 100644
index 00000000..6aed1cc1
--- /dev/null
+++ b/ide/vs2019/mimalloc-test-stress.vcxproj
@@ -0,0 +1,159 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {FEF7958F-750E-4C21-A04D-22707CC66878}
+ mimalloc-test-stress
+ 10.0
+ mimalloc-test-stress
+
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+
+
+ Console
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+
+
+ Console
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ %(PreprocessorDefinitions);NDEBUG
+
+
+ true
+ true
+ Console
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ %(PreprocessorDefinitions);NDEBUG
+
+
+ true
+ true
+ Console
+
+
+
+
+ false
+ false
+ false
+ false
+
+
+
+
+ {abb5eae7-b3e6-432e-b636-333449892ea6}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ide/vs2019/mimalloc-test.vcxproj b/ide/vs2019/mimalloc-test.vcxproj
new file mode 100644
index 00000000..1e901e45
--- /dev/null
+++ b/ide/vs2019/mimalloc-test.vcxproj
@@ -0,0 +1,163 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {FEF7858F-750E-4C21-A04D-22707CC66878}
+ mimalloctest
+ 10.0
+ mimalloc-test
+
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+ Application
+ true
+ v142
+
+
+ Application
+ false
+ v142
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+ stdcpp17
+
+
+ Console
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\include
+ stdcpp17
+
+
+ Console
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ _MBCS;%(PreprocessorDefinitions);NDEBUG
+ stdcpp17
+
+
+ true
+ true
+ Console
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\include
+ _MBCS;%(PreprocessorDefinitions);NDEBUG
+ stdcpp17
+
+
+ true
+ true
+ Console
+
+
+
+
+ AssemblyAndSourceCode
+ AssemblyAndSourceCode
+ AssemblyAndSourceCode
+ AssemblyAndSourceCode
+
+
+
+
+ {abb5eae7-b3e6-432e-b636-333449892ea6}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ide/vs2019/mimalloc.sln b/ide/vs2019/mimalloc.sln
new file mode 100644
index 00000000..aeab6b88
--- /dev/null
+++ b/ide/vs2019/mimalloc.sln
@@ -0,0 +1,71 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28010.2016
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32
+ {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32
+ {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32
+ {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32
+ {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A}
+ EndGlobalSection
+EndGlobal
diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj
new file mode 100644
index 00000000..4d9563c2
--- /dev/null
+++ b/ide/vs2019/mimalloc.vcxproj
@@ -0,0 +1,252 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {ABB5EAE7-B3E6-432E-B636-333449892EA6}
+ mimalloc
+ 10.0
+ mimalloc
+
+
+
+ StaticLibrary
+ true
+ v142
+
+
+ StaticLibrary
+ false
+ v142
+ true
+
+
+ StaticLibrary
+ true
+ v142
+
+
+ StaticLibrary
+ false
+ v142
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .lib
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .lib
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .lib
+
+
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\
+ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\
+ .lib
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ../../include
+ MI_DEBUG=3;%(PreprocessorDefinitions);
+ Default
+ false
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ../../include
+ MI_DEBUG=3;%(PreprocessorDefinitions);
+ Default
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ../../include
+ %(PreprocessorDefinitions);NDEBUG
+ AssemblyAndSourceCode
+ $(IntDir)
+ false
+ false
+ AnySuitable
+ Neither
+ false
+ false
+ Default
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ../../include
+ %(PreprocessorDefinitions);NDEBUG
+ AssemblyAndSourceCode
+ $(IntDir)
+ false
+ false
+ AnySuitable
+ Neither
+ false
+ false
+ Default
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ false
+ false
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/include/mimalloc.h b/include/mimalloc.h
index c1a3bbe6..46392302 100644
--- a/include/mimalloc.h
+++ b/include/mimalloc.h
@@ -229,6 +229,7 @@ typedef enum mi_option_e {
mi_option_decommit,
mi_option_large_os_pages,
mi_option_reserve_huge_os_pages,
+ mi_option_segment_cache,
mi_option_page_reset,
mi_option_cache_reset,
mi_option_reset_decommits,
diff --git a/src/options.c b/src/options.c
index c56b6bd7..6339d6e0 100644
--- a/src/options.c
+++ b/src/options.c
@@ -24,6 +24,9 @@ int mi_version(void) mi_attr_noexcept {
// --------------------------------------------------------
// Options
+// These can be accessed by multiple threads and may be
+// concurrently initialized, but an initializing data race
+// is ok since they resolve to the same value.
// --------------------------------------------------------
typedef enum mi_init_e {
UNINIT, // not yet initialized
@@ -63,6 +66,7 @@ static mi_option_desc_t options[_mi_option_last] =
{ 0, UNINIT, MI_OPTION(decommit) },
{ 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's
{ 0, UNINIT, MI_OPTION(reserve_huge_os_pages) },
+ { 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread
{ 0, UNINIT, MI_OPTION(page_reset) },
{ 0, UNINIT, MI_OPTION(cache_reset) },
{ 0, UNINIT, MI_OPTION(reset_decommits) } // note: cannot enable this if secure is on
@@ -227,27 +231,18 @@ static void mi_strlcat(char* dest, const char* src, size_t dest_size) {
// On Windows use GetEnvironmentVariable instead of getenv to work
// reliably even when this is invoked before the C runtime is initialized.
// i.e. when `_mi_preloading() == true`.
+// Note: on windows, environment names are not case sensitive.
#include
static bool mi_getenv(const char* name, char* result, size_t result_size) {
result[0] = 0;
- bool ok = (GetEnvironmentVariableA(name, result, (DWORD)result_size) > 0);
- if (!ok) {
- char buf[64+1];
- size_t len = strlen(name);
- if (len >= sizeof(buf)) len = sizeof(buf) - 1;
- for (size_t i = 0; i < len; i++) {
- buf[i] = toupper(name[i]);
- }
- buf[len] = 0;
- ok = (GetEnvironmentVariableA(name, result, (DWORD)result_size) > 0);
- }
- return ok;
+ size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size);
+ return (len > 0 && len < result_size);
}
#else
static bool mi_getenv(const char* name, char* result, size_t result_size) {
- #pragma warning(suppress:4996)
const char* s = getenv(name);
if (s == NULL) {
+ // in unix environments we check the upper case name too.
char buf[64+1];
size_t len = strlen(name);
if (len >= sizeof(buf)) len = sizeof(buf) - 1;
@@ -255,7 +250,6 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) {
buf[i] = toupper(name[i]);
}
buf[len] = 0;
- #pragma warning(suppress:4996)
s = getenv(buf);
}
if (s != NULL && strlen(s) < result_size) {
@@ -267,8 +261,7 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) {
}
}
#endif
-static void mi_option_init(mi_option_desc_t* desc) {
- desc->init = DEFAULTED;
+static void mi_option_init(mi_option_desc_t* desc) {
// Read option value from the environment
char buf[64+1];
mi_strlcpy(buf, "mimalloc_", sizeof(buf));
@@ -298,7 +291,12 @@ static void mi_option_init(mi_option_desc_t* desc) {
}
else {
_mi_warning_message("environment option mimalloc_%s has an invalid value: %s\n", desc->name, buf);
+ desc->init = DEFAULTED;
}
}
}
+ else {
+ desc->init = DEFAULTED;
+ }
+ mi_assert_internal(desc->init != UNINIT);
}
diff --git a/src/page.c b/src/page.c
index 68312f81..4b8d92c6 100644
--- a/src/page.c
+++ b/src/page.c
@@ -396,7 +396,7 @@ void _mi_page_retire(mi_page_t* page) {
// is the only page left with free blocks. It is not clear
// how to check this efficiently though... for now we just check
// if its neighbours are almost fully used.
- if (mi_likely(page->block_size <= 32*MI_INTPTR_SIZE)) {
+ if (mi_likely(page->block_size <= (MI_SMALL_SIZE_MAX/4))) {
if (mi_page_mostly_used(page->prev) && mi_page_mostly_used(page->next)) {
_mi_stat_counter_increase(&_mi_stats_main.page_no_retire,1);
return; // dont't retire after all
@@ -705,7 +705,11 @@ void mi_register_deferred_free(mi_deferred_free_fun* fn) mi_attr_noexcept {
General allocation
----------------------------------------------------------- */
-// Large and huge pages are allocated directly
+// Large and huge page allocation.
+// Huge pages are allocated directly without being in a queue.
+// Because huge pages contain just one block, and the segment contains
+// just that page, we always treat them as abandoned and any thread
+// that frees the block can free the whole page and segment directly.
static mi_page_t* mi_large_page_alloc(mi_heap_t* heap, size_t size) {
size_t block_size = _mi_wsize_from_size(size) * sizeof(uintptr_t);
mi_assert_internal(_mi_bin(block_size) == MI_BIN_HUGE);
diff --git a/src/segment.c b/src/segment.c
index 4a52f5a4..e9356a7c 100644
--- a/src/segment.c
+++ b/src/segment.c
@@ -289,8 +289,6 @@ static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) {
// The thread local segment cache is limited to be at most 1/8 of the peak size of segments in use,
-// and no more than 1.
-#define MI_SEGMENT_CACHE_MAX (4)
#define MI_SEGMENT_CACHE_FRACTION (8)
// note: returned segment may be partially reset
@@ -306,15 +304,18 @@ static mi_segment_t* mi_segment_cache_pop(size_t segment_slices, mi_segments_tld
return segment;
}
-static bool mi_segment_cache_full(mi_segments_tld_t* tld) {
- if (tld->cache_count < MI_SEGMENT_CACHE_MAX
- && tld->cache_count < (1 + (tld->peak_count / MI_SEGMENT_CACHE_FRACTION))
- ) { // always allow 1 element cache
+static bool mi_segment_cache_full(mi_segments_tld_t* tld)
+{
+ if (tld->count == 1 && tld->cache_count==0) return false; // always cache at least the final segment of a thread
+ size_t max_cache = mi_option_get(mi_option_segment_cache);
+ if (tld->cache_count < max_cache
+ && tld->cache_count < (1 + (tld->peak_count / MI_SEGMENT_CACHE_FRACTION)) // at least allow a 1 element cache
+ ) {
return false;
}
// take the opportunity to reduce the segment cache if it is too large (now)
// TODO: this never happens as we check against peak usage, should we use current usage instead?
- while (tld->cache_count > MI_SEGMENT_CACHE_MAX ) { //(1 + (tld->peak_count / MI_SEGMENT_CACHE_FRACTION))) {
+ while (tld->cache_count > max_cache) { //(1 + (tld->peak_count / MI_SEGMENT_CACHE_FRACTION))) {
mi_segment_t* segment = mi_segment_cache_pop(0,tld);
mi_assert_internal(segment != NULL);
if (segment != NULL) mi_segment_os_free(segment, tld);
@@ -922,19 +923,12 @@ static mi_page_t* mi_segment_huge_page_alloc(size_t size, mi_segments_tld_t* tld
/* -----------------------------------------------------------
Page allocation and free
----------------------------------------------------------- */
-/*
-static bool mi_is_good_fit(size_t bsize, size_t size) {
- // good fit if no more than 25% wasted
- return (bsize > 0 && size > 0 && bsize < size && (size - (size % bsize)) < (size/4));
-}
-*/
-
mi_page_t* _mi_segment_page_alloc(size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) {
mi_page_t* page;
- if (block_size <= MI_SMALL_OBJ_SIZE_MAX) {// || mi_is_good_fit(block_size,MI_SMALL_PAGE_SIZE)) {
+ if (block_size <= MI_SMALL_OBJ_SIZE_MAX) {
page = mi_segments_page_alloc(MI_PAGE_SMALL,block_size,tld,os_tld);
}
- else if (block_size <= MI_MEDIUM_OBJ_SIZE_MAX) {// || mi_is_good_fit(block_size, MI_MEDIUM_PAGE_SIZE)) {
+ else if (block_size <= MI_MEDIUM_OBJ_SIZE_MAX) {
page = mi_segments_page_alloc(MI_PAGE_MEDIUM,MI_MEDIUM_PAGE_SIZE,tld, os_tld);
}
else if (block_size <= MI_LARGE_OBJ_SIZE_MAX) {