PHP按200KB固定内存大小拆分数组为最少块数
实现数组按序列化大小拆分的最优方案
要实现将大数组拆分为数量最少的子数组块(每个块序列化后不超过200KB),核心思路是让每个子数组尽可能接近内存上限,具体实现步骤如下:
关键思路
- 先将内存限制转换为字节单位:200KB = 204800 字节
- 先估算单个元素的序列化平均大小,快速得到每个块的初始元素数量,避免逐次试探的低效
- 对初始数量进行动态调整,找到当前范围内能容纳的最大元素数,确保序列化后不超过限制
- 循环拆分原数组,直到所有元素都被分配到子块中
代码实现
// 定义内存上限:200KB 转字节 define('MAX_SERIALIZED_SIZE', 200 * 1024); $profileIds = range(1, 8000); // 示例数组 $chunks = []; $totalElements = count($profileIds); $currentIndex = 0; // 先估算单个元素的平均序列化大小(取前10个元素计算) $sample = array_slice($profileIds, 0, min(10, $totalElements)); $sampleSize = mb_strlen(serialize($sample), '8bit'); $avgElementSize = $sampleSize / count($sample); // 计算初始的每个块元素数量(留出一定冗余,避免直接踩上限) $initialChunkSize = floor(MAX_SERIALIZED_SIZE / $avgElementSize) - 1; $initialChunkSize = max(1, $initialChunkSize); // 确保至少1个元素 while ($currentIndex < $totalElements) { // 尝试当前最大可能的元素数 $remainingElements = $totalElements - $currentIndex; $chunkSize = min($initialChunkSize, $remainingElements); // 调整chunkSize,确保序列化后不超过限制 while (true) { $currentChunk = array_slice($profileIds, $currentIndex, $chunkSize); $currentSize = mb_strlen(serialize($currentChunk), '8bit'); if ($currentSize <= MAX_SERIALIZED_SIZE) { // 尝试能否再添加元素(如果还有剩余) if ($chunkSize < $remainingElements) { $testChunk = array_slice($profileIds, $currentIndex, $chunkSize + 1); $testSize = mb_strlen(serialize($testChunk), '8bit'); if ($testSize <= MAX_SERIALIZED_SIZE) { $chunkSize++; continue; } } break; } else { // 超过限制,减少元素数 $chunkSize--; if ($chunkSize === 0) { // 极端情况:单个元素就超过限制,这里可以抛出异常或单独处理 throw new Exception("单个元素序列化后超过内存上限"); } } } // 将符合条件的块加入结果 $chunks[] = array_slice($profileIds, $currentIndex, $chunkSize); $currentIndex += $chunkSize; // 更新初始chunkSize为当前找到的最大值,优化后续循环 $initialChunkSize = $chunkSize; } // 输出结果验证 foreach ($chunks as $i => $chunk) { echo "块 " . ($i+1) . " 元素数:" . count($chunk) . ",序列化大小:" . mb_strlen(serialize($chunk), '8bit') . "字节\n"; }
代码说明
- 初始估算:通过前10个元素计算平均大小,快速得到初始块大小,避免从1开始逐个试探的低效
- 动态调整:先验证初始块大小,若超过上限则减少,若还有剩余空间则尝试增加元素,确保每个块都用到最大允许的内存
- 极端情况处理:如果单个元素序列化后就超过200KB,会抛出异常,你可以根据实际需求修改这部分逻辑(比如单独存储该元素)
- 效率优化:每次找到合适的块大小后,将其作为下一次的初始值,减少后续的调整次数
内容的提问来源于stack exchange,提问作者Md. Zayed Hassan
相关产品推荐
相关产品推荐

