From 21d58357f2a7dc206522d8d66446decc503786f4 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Tue, 28 Aug 2018 13:06:36 +0200 Subject: [PATCH] logic: fixed application crash on windows if JVM tries to allocate too much memory by reducing the amount of allocated memory to the available size. --- src/lib/CMakeLists.txt | 2 + src/lib/utility/utilityWindows.cpp | 46 +++++++++++++++++++ src/lib/utility/utilityWindows.h | 13 ++++++ .../parser/java/JavaEnvironmentFactory.cpp | 18 +++++++- 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/lib/utility/utilityWindows.cpp create mode 100644 src/lib/utility/utilityWindows.h diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 302a6545..fab08aca 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -616,6 +616,8 @@ add_files( utility/utilityMath.h utility/utilityUuid.cpp utility/utilityUuid.h + utility/utilityWindows.cpp + utility/utilityWindows.h utility/utilityXml.cpp utility/utilityXml.h diff --git a/src/lib/utility/utilityWindows.cpp b/src/lib/utility/utilityWindows.cpp new file mode 100644 index 00000000..be63770b --- /dev/null +++ b/src/lib/utility/utilityWindows.cpp @@ -0,0 +1,46 @@ +#include "utility/utilityWindows.h" + +#ifdef WIN32 + +#include + +unsigned long utility::getLargestByteSizeOfAllocatableMemory() +{ + MEMORY_BASIC_INFORMATION mbi; + unsigned long start = 0; + bool recording = false; + unsigned long freestart = 0, largestFreestart = 0; + __int64 free = 0, largestFree = 0; + + while (true) + { + SIZE_T s = VirtualQuery((LPCVOID)start, &mbi, sizeof(mbi)); + if (s != sizeof(mbi)) break; + + if (mbi.State == MEM_FREE) + { + if (!recording) freestart = start; + + free += mbi.RegionSize; + recording = true; + } + else + { + if (recording) + { + if (free > largestFree) + { + largestFree = free; + largestFreestart = freestart; + } + } + free = 0; + recording = false; + } + start += mbi.RegionSize; + } + + return largestFree; +} + +#endif // WIN32 diff --git a/src/lib/utility/utilityWindows.h b/src/lib/utility/utilityWindows.h new file mode 100644 index 00000000..c2c0abcb --- /dev/null +++ b/src/lib/utility/utilityWindows.h @@ -0,0 +1,13 @@ +#ifndef UTILITY_WINDOWS_H +#define UTILITY_WINDOWS_H + +#ifdef WIN32 + +namespace utility +{ + unsigned long getLargestByteSizeOfAllocatableMemory(); +} + +#endif // WIN32 + +#endif // UTILITY_WINDOWS_H diff --git a/src/lib_java/data/parser/java/JavaEnvironmentFactory.cpp b/src/lib_java/data/parser/java/JavaEnvironmentFactory.cpp index ded0995d..bff5a2fd 100644 --- a/src/lib_java/data/parser/java/JavaEnvironmentFactory.cpp +++ b/src/lib_java/data/parser/java/JavaEnvironmentFactory.cpp @@ -8,6 +8,7 @@ #include "settings/ApplicationSettings.h" #include "utility/logging/logging.h" #include "utility/utilityLibrary.h" +#include "utility/utilityWindows.h" void JavaEnvironmentFactory::createInstance(std::string classPath, std::string& errorString) { @@ -41,7 +42,22 @@ void JavaEnvironmentFactory::createInstance(std::string classPath, std::string& s_classPath = classPath; - const int jvmMaximumMemory = ApplicationSettings::getInstance()->getJavaMaximumMemory(); + int jvmMaximumMemory = ApplicationSettings::getInstance()->getJavaMaximumMemory(); + +#ifdef WIN32 + if (jvmMaximumMemory > 0) + { + const float underestimationFactor = 0.8f; + const int maximumMB = utility::getLargestByteSizeOfAllocatableMemory() / 1024 / 1024 * underestimationFactor; + if (jvmMaximumMemory > maximumMB) + { + LOG_WARNING("Selected amount of maximum JVM memory of " + std::to_string(jvmMaximumMemory) + " MB exceeds maximum allocatable " + "memory on system. Correcting selected value to " + std::to_string(maximumMB) + " MB."); + jvmMaximumMemory = maximumMB; + } + } +#endif // WIN32 + const int optionCount = (jvmMaximumMemory < 0 ? 2 : 3); const std::string maximumMemoryOprionString = "-Xmx" + std::to_string(jvmMaximumMemory) + "m";