Unreal Engine中AWS SDK S3 GetObjectAsync因ResponseStream崩溃的解决方法
问题描述
在Unreal Engine中使用AWS SDK for C++(v1.9+)从S3异步下载文件时,程序始终在aws_cpp_sdk_core的Aws::Utils::Stream::ResponseStream::ReleaseStream()函数处崩溃,相关代码如下:
bool AWSBucketOperations::GetObjectAsync( const S3Client& ClientObject, const Aws::String& objectKey, const Aws::String& fromBucket, const Aws::String& outputFilePath, const std::function<void(const Aws::S3::Model::GetObjectOutcome& ObjectOutcome)>& callback) { Aws::S3::Model::GetObjectRequest Request; Request.SetBucket(fromBucket); Request.SetKey(objectKey); Request.SetResponseStreamFactory([=]() { return Aws::New<Aws::FStream>( "S3DownloadTag", outputFilePath, std::ios_base::out | std::ios_base::binary ); }); ClientObject->GetObjectAsync(Request, [callback]( const Aws::S3::S3Client*, const Aws::S3::Model::GetObjectRequest&, const Aws::S3::Model::GetObjectOutcome& outcome, const std::shared_ptr<const Aws::Client::AsyncCallerContext>&) { if (outcome.IsSuccess()) { callback(outcome); } else { callback(outcome); } }); return true; }
解决方案
1. 修正S3Client参数类型错误
原代码中ClientObject是const S3Client&引用类型,却使用指针运算符->调用GetObjectAsync,这会导致非法内存访问,是崩溃的核心原因之一。将参数改为指针或智能指针类型:
// 改为指针类型 bool AWSBucketOperations::GetObjectAsync( const Aws::S3::S3Client* ClientObject, // ... 其他参数不变 ) // 或者改为智能指针引用 bool AWSBucketOperations::GetObjectAsync( const std::shared_ptr<Aws::S3::S3Client>& ClientObject, // ... 其他参数不变 )
2. 校验文件流创建有效性
如果Aws::FStream未能成功打开目标文件,返回的无效流会导致SDK在ReleaseStream时访问空指针或非法内存。添加文件打开状态检查:
Request.SetResponseStreamFactory([=]() { auto stream = Aws::New<Aws::FStream>( "S3DownloadTag", outputFilePath, std::ios_base::out | std::ios_base::binary ); // 检查文件是否成功打开 if (!stream->is_open()) { Aws::Delete(stream); // 释放无效流 return static_cast<Aws::IOStream*>(nullptr); } return stream; });
3. 适配Unreal内存模型
确保AWS SDK是针对Unreal Engine编译的,使用Unreal的内存分配器(而非标准C++分配器)。若SDK编译时未适配Unreal,可能引发内存管理冲突,触发ReleaseStream时的崩溃。
4. 异步回调的线程安全
AWS SDK的异步回调运行在工作线程中,若callback中涉及Unreal的UObject操作,必须切换到游戏线程执行,避免跨线程访问导致的未定义行为:
// 示例:在回调中切换到游戏线程 [callback]( const Aws::S3::S3Client*, const Aws::S3::Model::GetObjectRequest&, const Aws::S3::Model::GetObjectOutcome& outcome, const std::shared_ptr<const Aws::Client::AsyncCallerContext>&) { // 用Unreal的线程调度器切换到游戏线程 AsyncTask(ENamedThreads::GameThread, [callback, outcome]() { callback(outcome); }); }
内容的提问来源于stack exchange,提问作者Alper Gunes
相关产品推荐
相关产品推荐

