Laravel 内存优化方法
数据库查询优化
// ❌ 不推荐:加载所有字段
$users = User::all();
// ✅ 推荐:只选择需要的字段
$users = User::select('id', 'name', 'email')->get();
// ❌ 不推荐:N+1查询问题
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // 每次循环都会查询
}
// ✅ 推荐:使用预加载
$posts = Post::with('author')->get();
// ✅ 使用延迟预加载
$posts = Post::all();
$posts->load('author');
// ✅ 使用chunk分批处理大量数据
User::chunk(100, function ($users) {
foreach ($users as $user) {
// 处理数据
}
});
使用游标处理大数据集
// ❌ 不推荐:一次性加载所有数据到内存
$users = User::all();
// ✅ 推荐:使用游标逐行处理
foreach (User::cursor() as $user) {
// 每次只处理一行数据
}
// ✅ 使用lazy集合
$users = User::lazy(100); // 每次加载100条
Redis缓存优化
// 使用Redis缓存减少数据库查询
Cache::store('redis')->remember('users.active', 3600, function () {
return User::where('active', true)->get();
});
// 缓存复杂查询结果
$users = Cache::tags(['users', 'active'])->remember('all', 3600, function () {
return User::with('profile')->where('active', true)->get();
});
队列处理耗时任务
// 将耗时任务加入队列
ProcessLargeFile::dispatch($filePath)->onQueue('high');
// 处理队列任务
class ProcessLargeFile implements ShouldQueue
{
use Queueable;
public function handle()
{
// 逐行处理大文件
$handle = fopen($this->filePath, 'r');
while (($line = fgets($handle)) !== false) {
// 处理每一行,不会占用大量内存
}
fclose($handle);
}
}
使用LazyCollection惰性集合
use Illuminate\Support\LazyCollection;
// 处理大文件时使用惰性集合
LazyCollection::make(function () {
$handle = fopen('large-file.csv', 'r');
while (($line = fgets($handle)) !== false) {
yield str_getcsv($line);
}
fclose($handle);
})->each(function ($row) {
// 每次只处理一行
});
Session存储优化
// config/session.php
// 使用更轻量的驱动
'driver' => env('SESSION_DRIVER', 'redis'),
// 减少session数据
// 不要存储不必要的大对象到session
Session::put('user_id', $user->id); // ✅ 只存ID
Session::put('user', $user); // ❌ 避免存储整个对象
View缓存和优化
// 启用视图缓存
php artisan view:cache
// 使用partial view减少内存
@include('partials.header') // 只加载需要的部分
// 避免在视图中执行复杂查询
// ❌ 视图模板中查询
@foreach(DB::table('users')->get() as $user)
// ✅ 在控制器中准备好数据
$users = User::all();
return view('users.index', compact('users'));
内存配置优化
// php.ini 配置
memory_limit = 256M // 根据服务器情况设置
// Laravel配置优化
// config/app.php
'debug' => env('APP_DEBUG', false), // 生产环境关闭debug
// 禁用不必要的服务提供者
'providers' => [
// 只保留需要的providers
// App\Providers\DebugServiceProvider::class, // 注释掉调试服务
]
GC优化和内存释放
// 手动触发垃圾回收
public function processLargeData()
{
$largeDataset = $this->getLargeData();
foreach ($largeDataset as $data) {
$this->processItem($data);
}
// 主动清空大变量
unset($largeDataset);
// 强制垃圾回收
gc_collect_cycles();
}
// 使用局部变量
public function storeUserData()
{
$userData = []; // 局部变量,函数结束后自动释放
for ($i = 0; $i < 1000; $i++) {
$userData[] = User::find($i);
}
// 处理数据...
}
资源管理优化
// 及时释放不必要的对象
public function generateReport()
{
$pdf = PDF::loadView('report', $data);
// 生成PDF后立即释放模板数据
unset($data);
return $pdf->download('report.pdf');
// 或使用回调
$pdf->download('report.pdf');
// 下载后PDF对象会自动销毁
}
// 使用finally确保资源释放
$file = fopen('large.log', 'r');
try {
while (($line = fgets($file)) !== false) {
// 处理
}
} finally {
fclose($file);
}
优化Eloquent模型
// 使用getDirty()避免不必要的数据加载
$user = User::find(1);
$user->name = 'New Name';
$user->save(); // 只更新改变的字段
// 使用withoutEvents跳过事件处理
User::withoutEvents(function () {
User::create(['name' => 'Test']); // 不触发事件
});
// 使用whereHas代替加载关联数据
// ❌
$users = User::with('posts')->get();
$users = $users->filter(function ($user) {
return $user->posts->count() > 5;
});
// ✅
$users = User::whereHas('posts', function ($query) {
$query->havingRaw('count(*) > 5');
})->get();
实时监控和调试
# 安装调试工具 composer require barryvdh/laravel-debugbar --dev # 查看内存使用 php artisan tinker > memory_get_usage(true); > memory_get_peak_usage(true);
配置文件优化
# .env 文件优化 APP_DEBUG=false DB_CONNECTION=pgsql SESSION_DRIVER=redis CACHE_DRIVER=redis # 减少不必要的数据加载 APP_URL=https://example.com
使用数据库原生查询
// 对于复杂查询,直接使用原生SQL
$users = DB::select('SELECT id, name FROM users WHERE active = ?', [1]);
// 使用DB门面减少ORM开销
$count = DB::table('users')->where('active', true)->count();
// 使用原生查询处理大数据
DB::unprepared('CREATE TEMPORARY TABLE temp_users AS SELECT * FROM...');
最佳实践总结:

- 优先使用LazyCollection处理大数据
- 启用OPcache和视图缓存
- 使用Redis/Memcached缓存
- 避免在循环中查询数据库
- 及时释放不再使用的变量
- 监控内存使用,设置合理限制
- 使用队列处理耗时任务
- 定期执行垃圾回收