From 2aa0000aba2a998c7729c403fbeb24aa23aa6375 Mon Sep 17 00:00:00 2001 From: Jesus Rojas Date: Thu, 11 Dec 2025 17:47:56 -0600 Subject: [PATCH 1/7] Replace mstats with task_info to measure memory usage --- FirebasePerformance/Sources/FPRNanoPbUtils.m | 8 +++++--- .../Gauges/Memory/FPRMemoryGaugeCollector.m | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/FirebasePerformance/Sources/FPRNanoPbUtils.m b/FirebasePerformance/Sources/FPRNanoPbUtils.m index 2f02fd3d15b..b47cfba03a4 100644 --- a/FirebasePerformance/Sources/FPRNanoPbUtils.m +++ b/FirebasePerformance/Sources/FPRNanoPbUtils.m @@ -363,9 +363,11 @@ firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray *gaugeData, NSString *ses memoryReadings[memoryReadingsCount].used_app_heap_memory_kb = (int32_t)BYTES_TO_KB(gaugeData.heapUsed); memoryReadings[memoryReadingsCount].has_used_app_heap_memory_kb = true; - memoryReadings[memoryReadingsCount].free_app_heap_memory_kb = - (int32_t)BYTES_TO_KB(gaugeData.heapAvailable); - memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true; + if (gaugeData.heapAvailable > 0) { + memoryReadings[memoryReadingsCount].free_app_heap_memory_kb = + (int32_t)BYTES_TO_KB(gaugeData.heapAvailable); + memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true; + } memoryReadingsCount++; } }]; diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index 7c4104d79f1..7b143d06f15 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -19,7 +19,7 @@ #import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" #import "FirebasePerformance/Sources/FPRConsoleLogger.h" -#include +#include @interface FPRMemoryGaugeCollector () @@ -37,10 +37,20 @@ @interface FPRMemoryGaugeCollector () FPRMemoryGaugeData *fprCollectMemoryMetric(void) { NSDate *collectionTime = [NSDate date]; - struct mstats ms = mstats(); + // Reading task_info is safer to call from any thread, including during high throughput networking activity. + task_vm_info_data_t vmInfo; + mach_msg_type_number_t count = TASK_VM_INFO_COUNT; + u_long usedBytes = 0; + u_long freeBytes = 0; + + kern_return_t kr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count); + if (kr == KERN_SUCCESS) { + // phys_footprint is the memory footprint used by Jetsam accounting. + usedBytes = (u_long)vmInfo.phys_footprint; + } FPRMemoryGaugeData *gaugeData = [[FPRMemoryGaugeData alloc] initWithCollectionTime:collectionTime - heapUsed:ms.bytes_used - heapAvailable:ms.bytes_free]; + heapUsed:usedBytes + heapAvailable:freeBytes]; return gaugeData; } From 2e88a7445df43323306eb3eda07c66287da33003 Mon Sep 17 00:00:00 2001 From: Jesus Rojas Date: Tue, 16 Dec 2025 19:41:17 -0600 Subject: [PATCH 2/7] Run style.sh --- .../Sources/Gauges/Memory/FPRMemoryGaugeCollector.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index 7b143d06f15..5a3483a3461 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -37,7 +37,8 @@ @interface FPRMemoryGaugeCollector () FPRMemoryGaugeData *fprCollectMemoryMetric(void) { NSDate *collectionTime = [NSDate date]; - // Reading task_info is safer to call from any thread, including during high throughput networking activity. + // Reading task_info is safer to call from any thread, including during high throughput networking + // activity. task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; u_long usedBytes = 0; From 9d78d2a32f1df059ec1142da24c43708ade7cc74 Mon Sep 17 00:00:00 2001 From: Jesus Rojas Date: Tue, 16 Dec 2025 19:44:44 -0600 Subject: [PATCH 3/7] clarity on comment --- .../Sources/Gauges/Memory/FPRMemoryGaugeCollector.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index 5a3483a3461..4973513f39c 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -37,8 +37,8 @@ @interface FPRMemoryGaugeCollector () FPRMemoryGaugeData *fprCollectMemoryMetric(void) { NSDate *collectionTime = [NSDate date]; - // Reading task_info is safer to call from any thread, including during high throughput networking - // activity. + // Using task_info(TASK_VM_INFO) avoids allocator-introspection (mstats/malloc_zone_statistics), + // which could crash under heavy allocation contention. it's safe to call from any thread. task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; u_long usedBytes = 0; From 74bfedc48a59e72703e8f705391800a1a1c6340c Mon Sep 17 00:00:00 2001 From: Jesus Rojas Date: Tue, 16 Dec 2025 20:04:03 -0600 Subject: [PATCH 4/7] Gemini Suggestions --- FirebasePerformance/Sources/FPRNanoPbUtils.m | 5 ----- .../Sources/Gauges/Memory/FPRMemoryGaugeCollector.m | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/FirebasePerformance/Sources/FPRNanoPbUtils.m b/FirebasePerformance/Sources/FPRNanoPbUtils.m index b47cfba03a4..57b8b0b248c 100644 --- a/FirebasePerformance/Sources/FPRNanoPbUtils.m +++ b/FirebasePerformance/Sources/FPRNanoPbUtils.m @@ -363,11 +363,6 @@ firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray *gaugeData, NSString *ses memoryReadings[memoryReadingsCount].used_app_heap_memory_kb = (int32_t)BYTES_TO_KB(gaugeData.heapUsed); memoryReadings[memoryReadingsCount].has_used_app_heap_memory_kb = true; - if (gaugeData.heapAvailable > 0) { - memoryReadings[memoryReadingsCount].free_app_heap_memory_kb = - (int32_t)BYTES_TO_KB(gaugeData.heapAvailable); - memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true; - } memoryReadingsCount++; } }]; diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index 4973513f39c..e3f54294af9 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -42,7 +42,6 @@ @interface FPRMemoryGaugeCollector () task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; u_long usedBytes = 0; - u_long freeBytes = 0; kern_return_t kr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count); if (kr == KERN_SUCCESS) { @@ -51,7 +50,7 @@ @interface FPRMemoryGaugeCollector () } FPRMemoryGaugeData *gaugeData = [[FPRMemoryGaugeData alloc] initWithCollectionTime:collectionTime heapUsed:usedBytes - heapAvailable:freeBytes]; + heapAvailable:0]; return gaugeData; } From 302cf06c757d4a1ec1f6e3ce99daad88bb7da023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rojas?= Date: Tue, 16 Dec 2025 20:07:08 -0600 Subject: [PATCH 5/7] Update FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../Sources/Gauges/Memory/FPRMemoryGaugeCollector.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index e3f54294af9..53ba77c4198 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -47,6 +47,8 @@ @interface FPRMemoryGaugeCollector () if (kr == KERN_SUCCESS) { // phys_footprint is the memory footprint used by Jetsam accounting. usedBytes = (u_long)vmInfo.phys_footprint; + } else { + FPRLogDebug(kFPRMemoryCollection, @"task_info() failed with error: %d", kr); } FPRMemoryGaugeData *gaugeData = [[FPRMemoryGaugeData alloc] initWithCollectionTime:collectionTime heapUsed:usedBytes From 036186eee5ef46b958b5045eb9b1b2aa82eafa09 Mon Sep 17 00:00:00 2001 From: Jesus Rojas Date: Tue, 16 Dec 2025 20:10:05 -0600 Subject: [PATCH 6/7] Update Comments - based on Gemini Suggestion --- .../Sources/Gauges/Memory/FPRMemoryGaugeData.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h index 747a4aac254..9143aba9d29 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h @@ -24,10 +24,12 @@ NS_ASSUME_NONNULL_BEGIN /** @brief Time at which memory data was measured. */ @property(nonatomic, readonly) NSDate *collectionTime; -/** @brief Heap memory that is used. */ +/** @brief Physical memory footprint of the application, measured via task_info phys_footprint. + * Note: This represents the total memory used by the process (as reported by Jetsam accounting), + * not just heap allocations. It includes heap, stack, memory-mapped files, and other resources. */ @property(nonatomic, readonly) u_long heapUsed; -/** @brief Heap memory that is available. */ +/** @brief Heap memory that is available. Always 0 as this metric is not available via task_info. */ @property(nonatomic, readonly) u_long heapAvailable; - (instancetype)init NS_UNAVAILABLE; @@ -36,8 +38,8 @@ NS_ASSUME_NONNULL_BEGIN * Creates an instance of memory gauge data with the provided information. * * @param collectionTime Time at which the gauge data was collected. - * @param heapUsed Heap memory that is used. - * @param heapAvailable Heap memory that is available. + * @param heapUsed Physical memory footprint of the application (measured via task_info phys_footprint). + * @param heapAvailable Heap memory that is available. Always 0 as this metric is not available. * @return Instance of memory gauge data. */ - (instancetype)initWithCollectionTime:(NSDate *)collectionTime From a622168955af0f7d037ae6de5c42ae5f6fde2413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rojas?= Date: Tue, 16 Dec 2025 20:12:31 -0600 Subject: [PATCH 7/7] Update FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../Sources/Gauges/Memory/FPRMemoryGaugeCollector.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m index 53ba77c4198..f3016f0eeee 100644 --- a/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m +++ b/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -41,7 +41,7 @@ @interface FPRMemoryGaugeCollector () // which could crash under heavy allocation contention. it's safe to call from any thread. task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; - u_long usedBytes = 0; + uint64_t usedBytes = 0; kern_return_t kr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count); if (kr == KERN_SUCCESS) {