使用LWP::UserAgent大文件PUT时的内存占用异常问题
解决LWP及S3相关模块传输大文件时内存暴涨崩溃的问题
问题现象
- 使用
LWP::UserAgent或依赖LWP的S3客户端(Paws::S3、Net::Amazon::S3::Client、Amazon::S3)传输大文件时,进程内存占用会暴涨至40GB以上,最终触发段错误崩溃。 - 单独分段读取待传输文件时,内存占用稳定在1.4GB以内,无异常;但加入LWP相关传输逻辑后内存显著上升,传输至55%时崩溃。
- S3类模块故障出现更早,内存随文件块传输逐步攀升,直至达到40GB阈值。
核心原因
LWP默认会将请求体全部加载到内存中缓存,即使你分段读取文件,只要以字符串形式传递内容给LWP,就会导致内存持续堆积。S3相关模块基于LWP实现时,若未启用流式上传,同样会把每个文件块的内容驻留在内存中,最终引发内存溢出。
解决方案
针对LWP::UserAgent的流式上传实现
直接绑定文件句柄作为请求内容,让LWP逐块读取并发送数据,避免加载整个文件到内存:
use LWP::UserAgent; my $ua = LWP::UserAgent->new; open my $fh, '<:raw', '/path/to/large_file' or die $!; my $response = $ua->post( 'http://your-server/upload-endpoint', Content => $fh, # 直接传递文件句柄实现流式发送 'Content-Length' => -s '/path/to/large_file', # 必须指定文件总大小 ); close $fh;
如果是分块上传,每块处理完毕后立即关闭对应句柄,避免句柄和内存堆积。
针对S3客户端模块的流式配置
所有依赖LWP的S3模块,需强制启用流式上传,避免块内容驻留内存:
- Paws::S3
use Paws; my $s3 = Paws->service('S3', region => 'your-region'); open my $fh, '<:raw', '/path/to/large_file' or die $!; $s3->PutObject( Bucket => 'your-bucket', Key => 'large_file_key', Body => $fh, # 传递文件句柄而非内容字符串 ContentLength => -s '/path/to/large_file' ); close $fh;
分块上传时,每个UploadPart需传递对应块的文件句柄(提前定位到块起始位置),上传完成后立即关闭句柄。
- Net::Amazon::S3::Client
use Net::Amazon::S3; use Net::Amazon::S3::Client; my $s3 = Net::Amazon::S3->new( aws_access_key_id => 'your-key', aws_secret_access_key => 'your-secret', ); my $client = Net::Amazon::S3::Client->new(s3 => $s3); my $bucket = $client->bucket(name => 'your-bucket'); open my $fh, '<:raw', '/path/to/large_file' or die $!; $bucket->add_key( 'large_file_key', $fh, # 流式传递文件句柄 { content_length => -s '/path/to/large_file' } ); close $fh;
额外检查点
- 避免在代码中重复赋值文件内容到变量,及时释放无用变量。
- 确认分块上传逻辑中,每个块的内容仅被读取一次,未被意外缓存。
内容的提问来源于stack exchange,提问作者Timothy R. Butler
相关产品推荐
相关产品推荐

