最近用Assimp加载较大OBJ模型时发现内存会爆满,看了下源码,问题在于解析OBJ文件时是一次解析全部 开辟的内存没有及时的释放 。
这是解析的源码
void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
// only update every 100KB or it'll be too slow
//const unsigned int updateProgressEveryBytes = 100 * 1024;
unsigned int progressCounter = 0;
const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
const unsigned int progressTotal = bytesToProcess;
unsigned int processed = 0;
size_t lastFilePos( 0 );
std::vector<char> buffer;
while ( streamBuffer.getNextDataLine( buffer, '\0' ) ) {
m_DataIt = buffer.begin();
m_DataItEnd = buffer.end();
// Handle progress reporting
const size_t filePos( streamBuffer.getFilePos() );
if ( lastFilePos < filePos ) {
processed = static_cast<unsigned int>(filePos);
lastFilePos = filePos;
progressCounter++;
m_progress->UpdateFileRead( processed, progressTotal );
}
// parse line
switch (*m_DataIt) {
case 'v': // Parse a vertex texture coordinate
{
++m_DataIt;
if (*m_DataIt == ' ' || *m_DataIt == '\t') {
size_t numComponents = getNumComponentsInDataDefinition();
if (numComponents == 3) {
// read in vertex definition
m_isVN = false;
getVector3(m_pModel->m_Vertices);
} else if (numComponents == 4) {
// read in vertex definition (homogeneous coords)
getHomogeneousVector3(m_pModel->m_Vertices);
} else if (numComponents == 6) {
// read vertex and vertex-color
getTwoVectors3(m_pModel->m_Vertices, m_pModel->m_VertexColors);
}
} else if (*m_DataIt == 't') {
// read in texture coordinate ( 2D or 3D )
++m_DataIt;
getVector( m_pModel->m_TextureCoord );
} else if (*m_DataIt == 'n') {
// Read in normal vector definition
++m_DataIt;
m_isVN = true;
getVector3( m_pModel->m_Normals );
}
}
break;
case 'p': // Parse a face, line or point statement
case 'l':
case 'f':
{
getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l'
? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
}
break;
case '#': // Parse a comment
{
getComment();
}
break;
case 'u': // Parse a material desc. setter
{
std::string name;
getNameNoSpace(m_DataIt, m_DataItEnd, name);
size_t nextSpace = name.find(" ");
if (nextSpace != std::string::npos)
name = name.substr(0, nextSpace);
if(name == "usemtl")
{
getMaterialDesc();
}
}
break;
case 'm': // Parse a material library or merging group ('mg')
{
std::string name;
getNameNoSpace(m_DataIt, m_DataItEnd, name);
size_t nextSpace = name.find(" ");
if (nextSpace != std::string::npos)
name = name.substr(0, nextSpace);
if (name == "mg")
getGroupNumberAndResolution();
else if(name == "mtllib")
getMaterialLib();
else
goto pf_skip_line;
}
break;
case 'g': // Parse group name
{
getGroupName();
}
break;
case 's': // Parse group number
{
getGroupNumber();
}
break;
case 'o': // Parse object name
{
getObjectName();
}
break;
default:
{
pf_skip_line:
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
}
}
m_filePath.push_back(m_curPath);
}
会在解析f的时候new出Face类型 直到文件读完 由于OJB文件较大所以会内存爆满
ObjFile::Face *face = new ObjFile::Face( type );
暂时优化的方案 按块现将face的数据写入文件里面保存 face直接释放
挡块多的时候要管理好路径,后面的赋值也方便
读出来直接从这个CreateDataFromImport(parser.GetModel(), pScene, pParser);函数里面赋值
这个函数也是按照块来赋值 ,在下面循环里读取并赋值给pModel->m_Meshes[index]->m_Faces。 也可以直接赋值个pScene 这样做比较麻烦要改大量代码
for (size_t index = 0; index < pModel->m_Objects.size(); ++index)
经过这个函数createNodes(pModel, pModel->m_Objects[index], pScene->mRootNode, pScene, MeshArray);之后要把之前赋值的pModel->m_Meshes[index]->m_Faces全部释放掉。