Add jemalloc support

Large graphical Qt applications heavily rely on heap allocations.
Jemalloc is a general-purpose malloc(3) implementation designed to
reduce heap fragmentation and improve scalability. It also provides
extensive tuning options.

Add a -jemalloc configure option, disabled by default. When enabled, Qt
and user code link to jemalloc, overriding the system's default
malloc().

Add cooperation with jemalloc for some Qt key classes: QArrayData (used
by QByteArray, QString and QList<T>), QBindingStoragePrivate,
QDataBuffer (used by the Qt Quick renderer), QDistanceFieldData,
QImageData, QObjectPrivate::TaggedSignalVector, QVarLengthArray.

This cooperation relies on two jemalloc-specific optimizations:
1. Efficient allocation via fittedMalloc():
   Determine the actual allocation size using nallocx(), then adjust the
   container’s capacity to match. This minimizes future reallocations.
   Note: we round allocSize to a multiple of sizeof(T) to ensure that
   we can later recompute the exact allocation size during deallocation.
2. Optimized deallocation via sizedFree():
   Use sdallocx(), which is faster than free when the allocation size
   is known, as it avoids internal size lookups.

Adapt the QVarLengthArray auto tests on capacity.

Non-standard functions docs are at https://jemalloc.net/jemalloc.3.html

[ChangeLog][QtCore] Added optional support for the jemalloc allocator,
and optimized memory allocations and deallocations in core Qt classes to
cooperate with it.

Change-Id: I6166e64e66876dee22662d3f3ea3e42a6647cfeb
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Aurélien Brooke 2025-01-24 17:09:58 +01:00
parent fc277e3ff6
commit 03d5daf943
17 changed files with 267 additions and 38 deletions

10
cmake/FindJeMalloc.cmake Normal file
View File

@ -0,0 +1,10 @@
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
find_package(PkgConfig QUIET)
pkg_check_modules(JeMalloc IMPORTED_TARGET "jemalloc")
if (NOT TARGET PkgConfig::JeMalloc)
set(JeMalloc_FOUND 0)
endif()

View File

@ -272,6 +272,7 @@ Core options:
-glib ................ Enable Glib support [no; auto on Unix] -glib ................ Enable Glib support [no; auto on Unix]
-inotify ............. Enable inotify support -inotify ............. Enable inotify support
-icu ................. Enable ICU support [auto] -icu ................. Enable ICU support [auto]
-jemalloc ............ Enable jemalloc support and cooperation [no]
-pcre ................ Select used libpcre2 [system/qt/no] -pcre ................ Select used libpcre2 [system/qt/no]
-zlib ................ Select used zlib [system/qt] -zlib ................ Select used zlib [system/qt]

View File

@ -40,6 +40,7 @@ qt_internal_add_module(Core
# Keep the rest alphabetical # Keep the rest alphabetical
compat/removed_api.cpp compat/removed_api.cpp
global/archdetect.cpp global/archdetect.cpp
global/qalloc.cpp global/qalloc.h
global/qassert.cpp global/qassert.h global/qassert.cpp global/qassert.h
global/qcheckedint_impl.h global/qcheckedint_impl.h
global/qcompare_impl.h global/qcompare_impl.h
@ -922,6 +923,11 @@ qt_internal_extend_target(Core CONDITION UNIX AND NOT MACOS AND NOT QT_FEATURE_i
text/qcollator_posix.cpp text/qcollator_posix.cpp
) )
qt_internal_extend_target(Core CONDITION QT_FEATURE_jemalloc
PUBLIC_LIBRARIES
PkgConfig::JeMalloc
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_regularexpression qt_internal_extend_target(Core CONDITION QT_FEATURE_regularexpression
SOURCES SOURCES
text/qregularexpression.cpp text/qregularexpression.h text/qregularexpression.cpp text/qregularexpression.h

View File

@ -35,6 +35,7 @@ qt_find_package(ICU 50.1 COMPONENTS i18n uc data PROVIDED_TARGETS ICU::i18n ICU:
if(QT_FEATURE_dlopen) if(QT_FEATURE_dlopen)
qt_add_qmake_lib_dependency(icu libdl) qt_add_qmake_lib_dependency(icu libdl)
endif() endif()
qt_find_package(JeMalloc PROVIDED_TARGETS PkgConfig::JeMalloc MODULE_NAME core QMAKE_LIB jemalloc)
qt_find_package(Libsystemd PROVIDED_TARGETS PkgConfig::Libsystemd MODULE_NAME core QMAKE_LIB journald) qt_find_package(Libsystemd PROVIDED_TARGETS PkgConfig::Libsystemd MODULE_NAME core QMAKE_LIB journald)
qt_find_package(WrapAtomic PROVIDED_TARGETS WrapAtomic::WrapAtomic MODULE_NAME core QMAKE_LIB libatomic) qt_find_package(WrapAtomic PROVIDED_TARGETS WrapAtomic::WrapAtomic MODULE_NAME core QMAKE_LIB libatomic)
qt_find_package(Libb2 PROVIDED_TARGETS Libb2::Libb2 MODULE_NAME core QMAKE_LIB libb2) qt_find_package(Libb2 PROVIDED_TARGETS Libb2::Libb2 MODULE_NAME core QMAKE_LIB libb2)
@ -733,6 +734,11 @@ qt_feature("ipc_posix"
) )
) )
qt_feature_definition("ipc_posix" "QT_POSIX_IPC") qt_feature_definition("ipc_posix" "QT_POSIX_IPC")
qt_feature("jemalloc" PUBLIC PRIVATE
LABEL "JeMalloc"
AUTODETECT OFF
CONDITION JeMalloc_FOUND
)
qt_feature("journald" PRIVATE qt_feature("journald" PRIVATE
LABEL "journald" LABEL "journald"
AUTODETECT OFF AUTODETECT OFF
@ -1172,6 +1178,7 @@ qt_configure_add_summary_entry(ARGS "system-doubleconversion")
qt_configure_add_summary_entry(ARGS "forkfd_pidfd" CONDITION LINUX) qt_configure_add_summary_entry(ARGS "forkfd_pidfd" CONDITION LINUX)
qt_configure_add_summary_entry(ARGS "glib") qt_configure_add_summary_entry(ARGS "glib")
qt_configure_add_summary_entry(ARGS "icu") qt_configure_add_summary_entry(ARGS "icu")
qt_configure_add_summary_entry(ARGS "jemalloc")
qt_configure_add_summary_entry(ARGS "timezone_tzdb") qt_configure_add_summary_entry(ARGS "timezone_tzdb")
qt_configure_add_summary_entry(ARGS "system-libb2") qt_configure_add_summary_entry(ARGS "system-libb2")
qt_configure_add_summary_entry(ARGS "mimetype-database") qt_configure_add_summary_entry(ARGS "mimetype-database")

View File

@ -0,0 +1,43 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qalloc.h"
#include <QtCore/qalgorithms.h>
#include <QtCore/qtpreprocessorsupport.h>
#include <cstdlib>
#if QT_CONFIG(jemalloc)
#include <jemalloc/jemalloc.h>
#endif
QT_BEGIN_NAMESPACE
size_t QtPrivate::expectedAllocSize(size_t allocSize, size_t alignment) noexcept
{
Q_ASSERT(qPopulationCount(alignment) == 1);
#if QT_CONFIG(jemalloc)
return ::nallocx(allocSize, MALLOCX_ALIGN(alignment));
#endif
Q_UNUSED(allocSize);
Q_UNUSED(alignment);
return 0;
}
void QtPrivate::sizedFree(void *ptr, size_t allocSize) noexcept
{
#if QT_CONFIG(jemalloc)
// jemalloc is okay with free(nullptr), as required by the standard,
// but will asssert (in debug) or invoke UB (in release) on sdallocx(nullptr, ...),
// so don't allow Qt to do that.
if (Q_LIKELY(ptr)) {
::sdallocx(ptr, allocSize, 0);
return;
}
#endif
Q_UNUSED(allocSize);
::free(ptr);
}
QT_END_NAMESPACE

128
src/corelib/global/qalloc.h Normal file
View File

@ -0,0 +1,128 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QALLOC_H
#define QALLOC_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qtcoreexports.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qtypeinfo.h>
#include <cstddef>
QT_BEGIN_NAMESPACE
namespace QtPrivate {
/**
* \internal
* \return the size that would be allocated for the given request.
*
* Computes the actual allocation size for \a allocSize and \a alignment,
* as determined by the active allocator, without performing the allocation.
*
* In practice, it only returns nonzero when using jemalloc.
*/
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
size_t expectedAllocSize(size_t allocSize, size_t alignment) noexcept;
/**
* \internal
* \brief Computes the best allocation size for the requested minimum capacity, and updates capacity.
*
* Computes the allocation size starting from \a headerSize and a requested minimum capacity in \a capacity,
* multiplied by the \a elementSize and adjusted by the \a unusedCapacity.
* The final capacity is written back into \a capacity.
* The \a headerSize and \a unusedCapacity values are not included in the final reported capacity.
*/
inline size_t fittedAllocSize(size_t headerSize, size_t *capacity,
size_t elementSize, size_t unusedCapacity, size_t alignment) noexcept
{
size_t totalCapacity = 0; // = capacity + unusedCapacity
if (Q_UNLIKELY(qAddOverflow(*capacity, unusedCapacity, &totalCapacity)))
return 0; // or handle error
size_t payloadSize = 0; // = totalCapacity * elementSize
if (Q_UNLIKELY(qMulOverflow(totalCapacity, elementSize, &payloadSize)))
return 0;
size_t allocSize = 0; // = headerSize + payloadSize
if (Q_UNLIKELY(qAddOverflow(headerSize, payloadSize, &allocSize)))
return 0;
if (size_t fittedSize = expectedAllocSize(allocSize, alignment); fittedSize != 0) {
// no need to overflow/underflow check from fittedSize,
// since allocSize <= fittedSize <= SIZE_T_MAX
*capacity = (fittedSize - headerSize) / elementSize - unusedCapacity;
size_t newTotalCapacity = *capacity + unusedCapacity;
size_t newPayloadSize = newTotalCapacity * elementSize;
return headerSize + newPayloadSize;
}
return allocSize;
}
#ifdef Q_CC_GNU
__attribute__((malloc))
#endif
inline void *fittedMalloc(size_t headerSize, size_t *capacity,
size_t elementSize, size_t unusedCapacity) noexcept
{
size_t allocSize = fittedAllocSize(headerSize, capacity,
elementSize, unusedCapacity, alignof(std::max_align_t));
if (Q_LIKELY(allocSize != 0))
return malloc(allocSize);
else
return nullptr;
}
inline void *fittedMalloc(size_t headerSize, qsizetype *capacity,
size_t elementSize, size_t unusedCapacity = 0) noexcept
{
size_t uCapacity = size_t(*capacity);
void *ptr = fittedMalloc(headerSize, &uCapacity, elementSize, unusedCapacity);
*capacity = qsizetype(uCapacity);
return ptr;
}
inline void *fittedRealloc(void *ptr, size_t headerSize, size_t *capacity,
size_t elementSize, size_t unusedCapacity) noexcept
{
size_t allocSize = fittedAllocSize(headerSize, capacity,
elementSize, unusedCapacity, alignof(std::max_align_t));
if (Q_LIKELY(allocSize != 0))
return realloc(ptr, allocSize);
else
return nullptr;
}
inline void *fittedRealloc(void *ptr, size_t headerSize, qsizetype *capacity,
size_t elementSize, size_t unusedCapacity = 0) noexcept
{
size_t uCapacity = size_t(*capacity);
ptr = fittedRealloc(ptr, headerSize, &uCapacity, elementSize, unusedCapacity);
*capacity = qsizetype(uCapacity);
return ptr;
}
Q_CORE_EXPORT void sizedFree(void *ptr, size_t allocSize) noexcept;
inline void sizedFree(void *ptr, size_t capacity, size_t elementSize) noexcept
{
sizedFree(ptr, capacity * elementSize);
}
} // namespace QtPrivate
QT_END_NAMESPACE
#endif // QALLOC_H

View File

@ -62,6 +62,7 @@
#define QT_FEATURE_itemmodel -1 #define QT_FEATURE_itemmodel -1
#define QT_FEATURE_islamiccivilcalendar -1 #define QT_FEATURE_islamiccivilcalendar -1
#define QT_FEATURE_jalalicalendar -1 #define QT_FEATURE_jalalicalendar -1
#define QT_FEATURE_jemalloc -1
#define QT_FEATURE_journald -1 #define QT_FEATURE_journald -1
#define QT_FEATURE_library -1 #define QT_FEATURE_library -1
#ifdef __linux__ #ifdef __linux__

View File

@ -20,6 +20,7 @@
// code lives here is that some special apps/libraries for e.g., QtJambi, // code lives here is that some special apps/libraries for e.g., QtJambi,
// Gammaray need access to the structs in this file. // Gammaray need access to the structs in this file.
#include <QtCore/qalloc.h>
#include <QtCore/qobject.h> #include <QtCore/qobject.h>
#include <QtCore/private/qobject_p.h> #include <QtCore/private/qobject_p.h>
@ -152,8 +153,9 @@ struct QObjectPrivate::ConnectionData
deleteOrphaned(c); deleteOrphaned(c);
SignalVector *v = signalVector.loadRelaxed(); SignalVector *v = signalVector.loadRelaxed();
if (v) { if (v) {
const size_t allocSize = sizeof(SignalVector) + (v->allocated + 1) * sizeof(ConnectionList);
v->~SignalVector(); v->~SignalVector();
free(v); QtPrivate::sizedFree(v, allocSize);
} }
} }
@ -179,13 +181,13 @@ struct QObjectPrivate::ConnectionData
return signalVector.loadRelaxed()->at(signal); return signalVector.loadRelaxed()->at(signal);
} }
void resizeSignalVector(uint size) void resizeSignalVector(size_t size)
{ {
SignalVector *vector = this->signalVector.loadRelaxed(); SignalVector *vector = this->signalVector.loadRelaxed();
if (vector && vector->allocated > size) if (vector && vector->allocated > size)
return; return;
size = (size + 7) & ~7; size = (size + 7) & ~7;
void *ptr = malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)); void *ptr = QtPrivate::fittedMalloc(sizeof(SignalVector), &size, sizeof(ConnectionList), 1);
auto newVector = new (ptr) SignalVector; auto newVector = new (ptr) SignalVector;
int start = -1; int start = -1;

View File

@ -6,6 +6,7 @@
#include <qscopedvaluerollback.h> #include <qscopedvaluerollback.h>
#include <QScopeGuard> #include <QScopeGuard>
#include <QtCore/qalloc.h>
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
#include <QThread> #include <QThread>
#include <QtCore/qmetaobject.h> #include <QtCore/qmetaobject.h>
@ -2212,7 +2213,8 @@ struct QBindingStoragePrivate
} }
} }
// data has been moved, no need to call destructors on old Pairs // data has been moved, no need to call destructors on old Pairs
free(d); const size_t oldAllocSize = sizeof(QBindingStorageData) + d->size*sizeof(Pair);
QtPrivate::sizedFree(d, oldAllocSize);
d = newData; d = newData;
} }
@ -2269,7 +2271,8 @@ struct QBindingStoragePrivate
p->~Pair(); p->~Pair();
++p; ++p;
} }
free(d); const size_t allocSize = sizeof(QBindingStorageData) + d->size*sizeof(Pair);
QtPrivate::sizedFree(d, allocSize);
} }
}; };

View File

@ -5,6 +5,7 @@ qt_commandline_option(doubleconversion TYPE enum VALUES no qt system)
qt_commandline_option(glib TYPE boolean) qt_commandline_option(glib TYPE boolean)
qt_commandline_option(icu TYPE boolean) qt_commandline_option(icu TYPE boolean)
qt_commandline_option(inotify TYPE boolean) qt_commandline_option(inotify TYPE boolean)
qt_commandline_option(jemalloc TYPE boolean)
qt_commandline_option(journald TYPE boolean) qt_commandline_option(journald TYPE boolean)
qt_commandline_option(libb2 TYPE enum VALUES no qt system) qt_commandline_option(libb2 TYPE enum VALUES no qt system)
qt_commandline_option(mimetype-database TYPE boolean) qt_commandline_option(mimetype-database TYPE boolean)

View File

@ -2,6 +2,7 @@
// Copyright (C) 2016 Intel Corporation. // Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qalloc.h>
#include <QtCore/qarraydata.h> #include <QtCore/qarraydata.h>
#include <QtCore/private/qnumeric_p.h> #include <QtCore/private/qnumeric_p.h>
#include <QtCore/private/qtools_p.h> #include <QtCore/private/qtools_p.h>
@ -101,12 +102,34 @@ qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizet
} else { } else {
bytes = qsizetype(morebytes); bytes = qsizetype(morebytes);
} }
size_t fittedBytes = QtPrivate::expectedAllocSize(bytes, alignof(std::max_align_t));
if (fittedBytes != 0)
bytes = fittedBytes;
result.elementCount = (bytes - headerSize) / elementSize; result.elementCount = (bytes - headerSize) / elementSize;
result.size = result.elementCount * elementSize + headerSize; result.size = result.elementCount * elementSize + headerSize;
return result; return result;
} }
using QtPrivate::AlignedQArrayData;
static qsizetype calculateHeaderSize(qsizetype alignment)
{
qsizetype headerSize = sizeof(AlignedQArrayData);
const qsizetype headerAlignment = alignof(AlignedQArrayData);
if (alignment > headerAlignment) {
// Allocate extra (alignment - Q_ALIGNOF(AlignedQArrayData)) padding
// bytes so we can properly align the data array. This assumes malloc is
// able to provide appropriate alignment for the header -- as it should!
// Effectively, we allocate one QTypedArrayData<T>::AlignmentDummy.
headerSize += alignment - headerAlignment;
}
Q_ASSERT(headerSize > 0);
return headerSize;
}
/* /*
Calculate the byte size for a block of \a capacity objects of size \a Calculate the byte size for a block of \a capacity objects of size \a
objectSize, with a header of size \a headerSize. If the \a option is objectSize, with a header of size \a headerSize. If the \a option is
@ -140,7 +163,6 @@ struct AllocationResult {
QArrayData *header; QArrayData *header;
}; };
} }
using QtPrivate::AlignedQArrayData;
static inline AllocationResult static inline AllocationResult
allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity, allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
@ -149,16 +171,7 @@ allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
if (capacity == 0) if (capacity == 0)
return {}; return {};
qsizetype headerSize = sizeof(AlignedQArrayData); const qsizetype headerSize = calculateHeaderSize(alignment);
const qsizetype headerAlignment = alignof(AlignedQArrayData);
if (alignment > headerAlignment) {
// Allocate extra (alignment - Q_ALIGNOF(AlignedQArrayData)) padding
// bytes so we can properly align the data array. This assumes malloc is
// able to provide appropriate alignment for the header -- as it should!
// Effectively, we allocate one QTypedArrayData<T>::AlignmentDummy.
headerSize += alignment - headerAlignment;
}
Q_ASSERT(headerSize > 0); Q_ASSERT(headerSize > 0);
auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option); auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
@ -248,10 +261,18 @@ void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
// Alignment is a power of two // Alignment is a power of two
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData)) Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
&& !(alignment & (alignment - 1))); && !(alignment & (alignment - 1)));
Q_UNUSED(objectSize);
Q_UNUSED(alignment);
::free(data); const qsizetype capacity = data->alloc;
const qsizetype headerSize = calculateHeaderSize(alignment);
Q_ASSERT(headerSize > 0);
const auto blockSize = calculateBlockSize(capacity, objectSize,
headerSize, QArrayData::KeepSize);
const qsizetype allocSize = blockSize.size;
if (Q_LIKELY(allocSize > 0))
QtPrivate::sizedFree(data, size_t(allocSize));
else // something went wrong, fallback to slow free()
free(data);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -9,6 +9,7 @@
#pragma qt_sync_stop_processing #pragma qt_sync_stop_processing
#endif #endif
#include <QtCore/qalloc.h>
#include <QtCore/qcompare.h> #include <QtCore/qcompare.h>
#include <QtCore/qcontainerfwd.h> #include <QtCore/qcontainerfwd.h>
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
@ -368,7 +369,7 @@ public:
if constexpr (QTypeInfo<T>::isComplex) if constexpr (QTypeInfo<T>::isComplex)
std::destroy_n(data(), size()); std::destroy_n(data(), size());
if (data() != reinterpret_cast<T *>(this->array)) if (data() != reinterpret_cast<T *>(this->array))
free(data()); QtPrivate::sizedFree(data(), capacity(), sizeof(T));
} }
inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other) inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
{ {
@ -729,9 +730,9 @@ Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
// resize(asize) // this requires a movable or copyable T, can't use, need to do it by hand // resize(asize) // this requires a movable or copyable T, can't use, need to do it by hand
if (asize > Prealloc) { if (asize > Prealloc) {
this->ptr = malloc(asize * sizeof(T));
Q_CHECK_PTR(this->ptr);
this->a = asize; this->a = asize;
this->ptr = QtPrivate::fittedMalloc(0, &this->a, sizeof(T));
Q_CHECK_PTR(this->ptr);
} }
if constexpr (QTypeInfo<T>::isComplex) if constexpr (QTypeInfo<T>::isComplex)
std::uninitialized_default_construct_n(data(), asize); std::uninitialized_default_construct_n(data(), asize);
@ -877,7 +878,7 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
void *newPtr; void *newPtr;
qsizetype newA; qsizetype newA;
if (aalloc > prealloc) { if (aalloc > prealloc) {
newPtr = malloc(aalloc * sizeof(T)); newPtr = QtPrivate::fittedMalloc(0, &aalloc, sizeof(T));
guard.reset(newPtr); guard.reset(newPtr);
Q_CHECK_PTR(newPtr); // could throw Q_CHECK_PTR(newPtr); // could throw
// by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here // by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
@ -902,7 +903,7 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
} }
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data()) if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data())
free(oldPtr); QtPrivate::sizedFree(oldPtr, osize, sizeof(T));
} }
template <class T> template <class T>

View File

@ -22,6 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <qpa/qplatformpixmap.h> #include <qpa/qplatformpixmap.h>
#include <qalloc.h>
#include <private/qcolorspace_p.h> #include <private/qcolorspace_p.h>
#include <private/qcolortransform_p.h> #include <private/qcolortransform_p.h>
#include <private/qmemrotate_p.h> #include <private/qmemrotate_p.h>
@ -162,7 +163,7 @@ QImageData::~QImageData()
QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no)); QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
delete paintEngine; delete paintEngine;
if (data && own_data) if (data && own_data)
free(data); QtPrivate::sizedFree(data, nbytes);
data = nullptr; data = nullptr;
} }

View File

@ -17,6 +17,7 @@
#include <QtGui/private/qtguiglobal_p.h> #include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qalloc.h"
#include "QtCore/qbytearray.h" #include "QtCore/qbytearray.h"
#include "QtCore/qtypeinfo.h" #include "QtCore/qtypeinfo.h"
@ -34,7 +35,7 @@ public:
if (res) { if (res) {
QT_WARNING_PUSH QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Walloc-size-larger-than=") QT_WARNING_DISABLE_GCC("-Walloc-size-larger-than=")
buffer = (Type*) malloc(capacity * sizeof(Type)); buffer = (Type*) QtPrivate::fittedMalloc(0, &capacity, sizeof(Type));
QT_WARNING_POP QT_WARNING_POP
Q_CHECK_PTR(buffer); Q_CHECK_PTR(buffer);
} else { } else {
@ -47,7 +48,7 @@ public:
{ {
static_assert(!QTypeInfo<Type>::isComplex); static_assert(!QTypeInfo<Type>::isComplex);
if (buffer) if (buffer)
free(buffer); QtPrivate::sizedFree(buffer, capacity, sizeof(Type));
} }
inline void reset() { siz = 0; } inline void reset() { siz = 0; }
@ -86,20 +87,21 @@ public:
capacity = 1; capacity = 1;
while (capacity < size) while (capacity < size)
capacity *= 2; capacity *= 2;
buffer = (Type*) realloc(static_cast<void*>(buffer), capacity * sizeof(Type)); buffer = (Type*) QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
Q_CHECK_PTR(buffer); Q_CHECK_PTR(buffer);
} }
} }
void shrink(qsizetype size) { void shrink(qsizetype size) {
Q_ASSERT(capacity >= size); Q_ASSERT(capacity >= size);
capacity = size;
if (size) { if (size) {
buffer = (Type*) realloc(static_cast<void*>(buffer), capacity * sizeof(Type)); capacity = size;
buffer = (Type*) QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
Q_CHECK_PTR(buffer); Q_CHECK_PTR(buffer);
siz = std::min(siz, size); siz = std::min(siz, size);
} else { } else {
free(buffer); QtPrivate::sizedFree(buffer, capacity, sizeof(Type));
capacity = size;
buffer = nullptr; buffer = nullptr;
siz = 0; siz = 0;
} }

View File

@ -3,6 +3,7 @@
#include "qdistancefield_p.h" #include "qdistancefield_p.h"
#include <qmath.h> #include <qmath.h>
#include <QtCore/qalloc.h>
#include <private/qdatabuffer_p.h> #include <private/qdatabuffer_p.h>
#include <private/qimage_p.h> #include <private/qimage_p.h>
#include <private/qpathsimplifier_p.h> #include <private/qpathsimplifier_p.h>
@ -826,7 +827,7 @@ QDistanceFieldData::QDistanceFieldData(const QDistanceFieldData &other)
QDistanceFieldData::~QDistanceFieldData() QDistanceFieldData::~QDistanceFieldData()
{ {
free(data); QtPrivate::sizedFree(data, nbytes);
} }
QDistanceFieldData *QDistanceFieldData::create(const QSize &size) QDistanceFieldData *QDistanceFieldData::create(const QSize &size)

View File

@ -17,6 +17,7 @@ qt_internal_add_sync_header_dependencies(Bootstrap Core)
qt_internal_extend_target(Bootstrap qt_internal_extend_target(Bootstrap
SOURCES SOURCES
../../corelib/global/qalloc.cpp
../../corelib/global/qassert.cpp ../../corelib/global/qassert.cpp
../../corelib/global/qtenvironmentvariables.cpp ../../corelib/global/qtenvironmentvariables.cpp
../../corelib/io/qabstractfileengine.cpp ../../corelib/io/qabstractfileengine.cpp

View File

@ -1171,11 +1171,11 @@ void tst_QVarLengthArray::squeeze()
list.resize(0); list.resize(0);
QCOMPARE(list.capacity(), sizeOnStack); QCOMPARE(list.capacity(), sizeOnStack);
list.resize(sizeOnHeap); list.resize(sizeOnHeap);
QCOMPARE(list.capacity(), sizeOnHeap); QCOMPARE_GE(list.capacity(), sizeOnHeap);
list.resize(sizeOnStack); list.resize(sizeOnStack);
QCOMPARE(list.capacity(), sizeOnHeap); QCOMPARE_GE(list.capacity(), sizeOnHeap);
list.resize(0); list.resize(0);
QCOMPARE(list.capacity(), sizeOnHeap); QCOMPARE_GE(list.capacity(), sizeOnHeap);
list.squeeze(); list.squeeze();
QCOMPARE(list.capacity(), sizeOnStack); QCOMPARE(list.capacity(), sizeOnStack);
list.resize(sizeOnStack); list.resize(sizeOnStack);
@ -1183,7 +1183,7 @@ void tst_QVarLengthArray::squeeze()
QCOMPARE(list.capacity(), sizeOnStack); QCOMPARE(list.capacity(), sizeOnStack);
list.resize(sizeOnHeap); list.resize(sizeOnHeap);
list.squeeze(); list.squeeze();
QCOMPARE(list.capacity(), sizeOnHeap); QCOMPARE_GE(list.capacity(), sizeOnHeap);
} }
void tst_QVarLengthArray::operators() void tst_QVarLengthArray::operators()
@ -1545,14 +1545,14 @@ void tst_QVarLengthArray::reserve()
arr.reserve(150); arr.reserve(150);
// Allocate memory on heap, as we reserve more than pre-allocated // Allocate memory on heap, as we reserve more than pre-allocated
QCOMPARE(arr.capacity(), 150); QCOMPARE_GE(arr.capacity(), 150);
QCOMPARE(arr.size(), 0); QCOMPARE(arr.size(), 0);
const auto *heapPtr = arr.constData(); const auto *heapPtr = arr.constData();
QVERIFY(heapPtr != stackPtr); QVERIFY(heapPtr != stackPtr);
arr.reserve(50); arr.reserve(50);
// Nothing changed // Nothing changed
QCOMPARE(arr.capacity(), 150); QCOMPARE_GE(arr.capacity(), 150);
QCOMPARE(arr.constData(), heapPtr); QCOMPARE(arr.constData(), heapPtr);
arr.squeeze(); arr.squeeze();