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:
parent
fc277e3ff6
commit
03d5daf943
10
cmake/FindJeMalloc.cmake
Normal file
10
cmake/FindJeMalloc.cmake
Normal 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()
|
@ -272,6 +272,7 @@ Core options:
|
||||
-glib ................ Enable Glib support [no; auto on Unix]
|
||||
-inotify ............. Enable inotify support
|
||||
-icu ................. Enable ICU support [auto]
|
||||
-jemalloc ............ Enable jemalloc support and cooperation [no]
|
||||
-pcre ................ Select used libpcre2 [system/qt/no]
|
||||
-zlib ................ Select used zlib [system/qt]
|
||||
|
||||
|
@ -40,6 +40,7 @@ qt_internal_add_module(Core
|
||||
# Keep the rest alphabetical
|
||||
compat/removed_api.cpp
|
||||
global/archdetect.cpp
|
||||
global/qalloc.cpp global/qalloc.h
|
||||
global/qassert.cpp global/qassert.h
|
||||
global/qcheckedint_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
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_jemalloc
|
||||
PUBLIC_LIBRARIES
|
||||
PkgConfig::JeMalloc
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_regularexpression
|
||||
SOURCES
|
||||
text/qregularexpression.cpp text/qregularexpression.h
|
||||
|
@ -35,6 +35,7 @@ qt_find_package(ICU 50.1 COMPONENTS i18n uc data PROVIDED_TARGETS ICU::i18n ICU:
|
||||
if(QT_FEATURE_dlopen)
|
||||
qt_add_qmake_lib_dependency(icu libdl)
|
||||
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(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)
|
||||
@ -733,6 +734,11 @@ qt_feature("ipc_posix"
|
||||
)
|
||||
)
|
||||
qt_feature_definition("ipc_posix" "QT_POSIX_IPC")
|
||||
qt_feature("jemalloc" PUBLIC PRIVATE
|
||||
LABEL "JeMalloc"
|
||||
AUTODETECT OFF
|
||||
CONDITION JeMalloc_FOUND
|
||||
)
|
||||
qt_feature("journald" PRIVATE
|
||||
LABEL "journald"
|
||||
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 "glib")
|
||||
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 "system-libb2")
|
||||
qt_configure_add_summary_entry(ARGS "mimetype-database")
|
||||
|
43
src/corelib/global/qalloc.cpp
Normal file
43
src/corelib/global/qalloc.cpp
Normal 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
128
src/corelib/global/qalloc.h
Normal 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
|
@ -62,6 +62,7 @@
|
||||
#define QT_FEATURE_itemmodel -1
|
||||
#define QT_FEATURE_islamiccivilcalendar -1
|
||||
#define QT_FEATURE_jalalicalendar -1
|
||||
#define QT_FEATURE_jemalloc -1
|
||||
#define QT_FEATURE_journald -1
|
||||
#define QT_FEATURE_library -1
|
||||
#ifdef __linux__
|
||||
|
@ -20,6 +20,7 @@
|
||||
// code lives here is that some special apps/libraries for e.g., QtJambi,
|
||||
// Gammaray need access to the structs in this file.
|
||||
|
||||
#include <QtCore/qalloc.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/private/qobject_p.h>
|
||||
|
||||
@ -152,8 +153,9 @@ struct QObjectPrivate::ConnectionData
|
||||
deleteOrphaned(c);
|
||||
SignalVector *v = signalVector.loadRelaxed();
|
||||
if (v) {
|
||||
const size_t allocSize = sizeof(SignalVector) + (v->allocated + 1) * sizeof(ConnectionList);
|
||||
v->~SignalVector();
|
||||
free(v);
|
||||
QtPrivate::sizedFree(v, allocSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,13 +181,13 @@ struct QObjectPrivate::ConnectionData
|
||||
return signalVector.loadRelaxed()->at(signal);
|
||||
}
|
||||
|
||||
void resizeSignalVector(uint size)
|
||||
void resizeSignalVector(size_t size)
|
||||
{
|
||||
SignalVector *vector = this->signalVector.loadRelaxed();
|
||||
if (vector && vector->allocated > size)
|
||||
return;
|
||||
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;
|
||||
|
||||
int start = -1;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <qscopedvaluerollback.h>
|
||||
#include <QScopeGuard>
|
||||
#include <QtCore/qalloc.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QThread>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
@ -2212,7 +2213,8 @@ struct QBindingStoragePrivate
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -2269,7 +2271,8 @@ struct QBindingStoragePrivate
|
||||
p->~Pair();
|
||||
++p;
|
||||
}
|
||||
free(d);
|
||||
const size_t allocSize = sizeof(QBindingStorageData) + d->size*sizeof(Pair);
|
||||
QtPrivate::sizedFree(d, allocSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ qt_commandline_option(doubleconversion TYPE enum VALUES no qt system)
|
||||
qt_commandline_option(glib TYPE boolean)
|
||||
qt_commandline_option(icu TYPE boolean)
|
||||
qt_commandline_option(inotify TYPE boolean)
|
||||
qt_commandline_option(jemalloc TYPE boolean)
|
||||
qt_commandline_option(journald TYPE boolean)
|
||||
qt_commandline_option(libb2 TYPE enum VALUES no qt system)
|
||||
qt_commandline_option(mimetype-database TYPE boolean)
|
||||
|
@ -2,6 +2,7 @@
|
||||
// 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
|
||||
|
||||
#include <QtCore/qalloc.h>
|
||||
#include <QtCore/qarraydata.h>
|
||||
#include <QtCore/private/qnumeric_p.h>
|
||||
#include <QtCore/private/qtools_p.h>
|
||||
@ -101,12 +102,34 @@ qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizet
|
||||
} else {
|
||||
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.size = result.elementCount * elementSize + headerSize;
|
||||
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
|
||||
objectSize, with a header of size \a headerSize. If the \a option is
|
||||
@ -140,7 +163,6 @@ struct AllocationResult {
|
||||
QArrayData *header;
|
||||
};
|
||||
}
|
||||
using QtPrivate::AlignedQArrayData;
|
||||
|
||||
static inline AllocationResult
|
||||
allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
|
||||
@ -149,16 +171,7 @@ allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
|
||||
if (capacity == 0)
|
||||
return {};
|
||||
|
||||
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;
|
||||
}
|
||||
const qsizetype headerSize = calculateHeaderSize(alignment);
|
||||
Q_ASSERT(headerSize > 0);
|
||||
|
||||
auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
|
||||
@ -248,10 +261,18 @@ void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
|
||||
// Alignment is a power of two
|
||||
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
|
||||
&& !(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
|
||||
|
@ -9,6 +9,7 @@
|
||||
#pragma qt_sync_stop_processing
|
||||
#endif
|
||||
|
||||
#include <QtCore/qalloc.h>
|
||||
#include <QtCore/qcompare.h>
|
||||
#include <QtCore/qcontainerfwd.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
@ -368,7 +369,7 @@ public:
|
||||
if constexpr (QTypeInfo<T>::isComplex)
|
||||
std::destroy_n(data(), size());
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
|
||||
if (asize > Prealloc) {
|
||||
this->ptr = malloc(asize * sizeof(T));
|
||||
Q_CHECK_PTR(this->ptr);
|
||||
this->a = asize;
|
||||
this->ptr = QtPrivate::fittedMalloc(0, &this->a, sizeof(T));
|
||||
Q_CHECK_PTR(this->ptr);
|
||||
}
|
||||
if constexpr (QTypeInfo<T>::isComplex)
|
||||
std::uninitialized_default_construct_n(data(), asize);
|
||||
@ -877,7 +878,7 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
|
||||
void *newPtr;
|
||||
qsizetype newA;
|
||||
if (aalloc > prealloc) {
|
||||
newPtr = malloc(aalloc * sizeof(T));
|
||||
newPtr = QtPrivate::fittedMalloc(0, &aalloc, sizeof(T));
|
||||
guard.reset(newPtr);
|
||||
Q_CHECK_PTR(newPtr); // could throw
|
||||
// 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())
|
||||
free(oldPtr);
|
||||
QtPrivate::sizedFree(oldPtr, osize, sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <qpa/qplatformpixmap.h>
|
||||
#include <qalloc.h>
|
||||
#include <private/qcolorspace_p.h>
|
||||
#include <private/qcolortransform_p.h>
|
||||
#include <private/qmemrotate_p.h>
|
||||
@ -162,7 +163,7 @@ QImageData::~QImageData()
|
||||
QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
|
||||
delete paintEngine;
|
||||
if (data && own_data)
|
||||
free(data);
|
||||
QtPrivate::sizedFree(data, nbytes);
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include "QtCore/qalloc.h"
|
||||
#include "QtCore/qbytearray.h"
|
||||
#include "QtCore/qtypeinfo.h"
|
||||
|
||||
@ -34,7 +35,7 @@ public:
|
||||
if (res) {
|
||||
QT_WARNING_PUSH
|
||||
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
|
||||
Q_CHECK_PTR(buffer);
|
||||
} else {
|
||||
@ -47,7 +48,7 @@ public:
|
||||
{
|
||||
static_assert(!QTypeInfo<Type>::isComplex);
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
QtPrivate::sizedFree(buffer, capacity, sizeof(Type));
|
||||
}
|
||||
|
||||
inline void reset() { siz = 0; }
|
||||
@ -86,20 +87,21 @@ public:
|
||||
capacity = 1;
|
||||
while (capacity < size)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void shrink(qsizetype size) {
|
||||
Q_ASSERT(capacity >= size);
|
||||
capacity = 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);
|
||||
siz = std::min(siz, size);
|
||||
} else {
|
||||
free(buffer);
|
||||
QtPrivate::sizedFree(buffer, capacity, sizeof(Type));
|
||||
capacity = size;
|
||||
buffer = nullptr;
|
||||
siz = 0;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "qdistancefield_p.h"
|
||||
#include <qmath.h>
|
||||
#include <QtCore/qalloc.h>
|
||||
#include <private/qdatabuffer_p.h>
|
||||
#include <private/qimage_p.h>
|
||||
#include <private/qpathsimplifier_p.h>
|
||||
@ -826,7 +827,7 @@ QDistanceFieldData::QDistanceFieldData(const QDistanceFieldData &other)
|
||||
|
||||
QDistanceFieldData::~QDistanceFieldData()
|
||||
{
|
||||
free(data);
|
||||
QtPrivate::sizedFree(data, nbytes);
|
||||
}
|
||||
|
||||
QDistanceFieldData *QDistanceFieldData::create(const QSize &size)
|
||||
|
@ -17,6 +17,7 @@ qt_internal_add_sync_header_dependencies(Bootstrap Core)
|
||||
|
||||
qt_internal_extend_target(Bootstrap
|
||||
SOURCES
|
||||
../../corelib/global/qalloc.cpp
|
||||
../../corelib/global/qassert.cpp
|
||||
../../corelib/global/qtenvironmentvariables.cpp
|
||||
../../corelib/io/qabstractfileengine.cpp
|
||||
|
@ -1171,11 +1171,11 @@ void tst_QVarLengthArray::squeeze()
|
||||
list.resize(0);
|
||||
QCOMPARE(list.capacity(), sizeOnStack);
|
||||
list.resize(sizeOnHeap);
|
||||
QCOMPARE(list.capacity(), sizeOnHeap);
|
||||
QCOMPARE_GE(list.capacity(), sizeOnHeap);
|
||||
list.resize(sizeOnStack);
|
||||
QCOMPARE(list.capacity(), sizeOnHeap);
|
||||
QCOMPARE_GE(list.capacity(), sizeOnHeap);
|
||||
list.resize(0);
|
||||
QCOMPARE(list.capacity(), sizeOnHeap);
|
||||
QCOMPARE_GE(list.capacity(), sizeOnHeap);
|
||||
list.squeeze();
|
||||
QCOMPARE(list.capacity(), sizeOnStack);
|
||||
list.resize(sizeOnStack);
|
||||
@ -1183,7 +1183,7 @@ void tst_QVarLengthArray::squeeze()
|
||||
QCOMPARE(list.capacity(), sizeOnStack);
|
||||
list.resize(sizeOnHeap);
|
||||
list.squeeze();
|
||||
QCOMPARE(list.capacity(), sizeOnHeap);
|
||||
QCOMPARE_GE(list.capacity(), sizeOnHeap);
|
||||
}
|
||||
|
||||
void tst_QVarLengthArray::operators()
|
||||
@ -1545,14 +1545,14 @@ void tst_QVarLengthArray::reserve()
|
||||
|
||||
arr.reserve(150);
|
||||
// Allocate memory on heap, as we reserve more than pre-allocated
|
||||
QCOMPARE(arr.capacity(), 150);
|
||||
QCOMPARE_GE(arr.capacity(), 150);
|
||||
QCOMPARE(arr.size(), 0);
|
||||
const auto *heapPtr = arr.constData();
|
||||
QVERIFY(heapPtr != stackPtr);
|
||||
|
||||
arr.reserve(50);
|
||||
// Nothing changed
|
||||
QCOMPARE(arr.capacity(), 150);
|
||||
QCOMPARE_GE(arr.capacity(), 150);
|
||||
QCOMPARE(arr.constData(), heapPtr);
|
||||
|
||||
arr.squeeze();
|
||||
|
Loading…
x
Reference in New Issue
Block a user