Cocos2dx的cache细节,资源路径不规范,容易导致cache中存在多份

简介: Cocos2dx的cache细节,资源路径不规范,容易导致cache中存在多份

SpriteFrameCache

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("");
复制代码

TextureCache

std::unordered_map<std::string, TexInfo*> _textures;
复制代码

key的来源

Texture2D * TextureCache::addImage(const std::string &path){
    std::string fullpath = GetFullPath(path);
    auto it = _textures.find(fullpath);
}
std::string GetFullPath(std::string path){
    std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path);
    if (fullPath.length() > 0){
        return fullPath;
    }else{
        return path;
    }
}
std::string FileUtils::fullPathForFilename(const std::string &filename) const
{
    if (path[0] == '/')
    {
        return filename;
    }
    std::string name = filename;
    int index = name.find("/../");
    while (index > 0) {
            int last = name.find_last_of("/", index-1);
            if (last > 0) {
                    name = name.substr(0, last) + name.substr(index+3, name.length());
            }
            else {
                    break;
            }
            index = name.find("/../");
    }
    // Already Cached ?
    auto cacheIter = _fullPathCache.find(name);
    // 又一个很重要的cache: mutable std::unordered_map<std::string, std::string> _fullPathCache;
    if(cacheIter != _fullPathCache.end())
    {
        return cacheIter->second;
    }
    // Get the new file name.
    const std::string newFilename(getNewFilename(name));
    std::string fullpath;
    for (const auto& searchIt : _searchPathArray){
        for (const auto& resolutionIt : _searchResolutionsOrderArray){
            fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt);
            if (!fullpath.empty()){
                // Using the filename passed in as key.
                _fullPathCache.emplace(name, fullpath);
                return fullpath;
            }
        }
    }
    return "";
}
复制代码

测试结果

网络异常,图片无法展示
|

  • name为ani1/test.png,在textureCache中的映射key为res/ani1/test.png
  • name为res/ani1/test.png,在textureCache中的映射key为exePath/res/ani1/test.png

相当于加载的是磁盘的同一份图片,结果却产生了2个纹理,理想情况是产生1份,产生这个问题的原因是:

TextureCache的key受filePathCache的影响,而filePathCache受searchPath的影响

searchPath的目录的顺序为:

  • exePath
  • src
  • res

ani1/test.png只能在res目录下找到,res/ani1/test.png只能在exePath目录下找到,所以最终2者的key是完全不同的。

造成这个问题是因为我设置了一个无效的searchPath,而在win32平台判断文件是否存在发生了异常

bool FileUtilsWin32::isFileExistInternal(const std::string& strFilePath) const
{
    if (strFilePath.empty())
    {
        return false;
    }
    std::string strPath = strFilePath;
    if (!isAbsolutePath(strPath))
    { // Not absolute path, add the default root path at the beginning.
        strPath.insert(0, _defaultResRootPath);
    }
    DWORD attr = GetFileAttributesW(StringUtf8ToWideChar(strPath).c_str());
    if(attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
        return false;   //  not a file
    return true;
}
复制代码

当strFile为res/ani1/test.png返回的是FILE_ATTRIBUTE_ARCHIVEisFileExistInternal直接返回了true,认为存在,准确说这个文件是相对于exe是存在的,但是这个路径不是完整路径

  • 测试代码:
char* file = "res/ani2/test.png"; // exe运行目录下真的有这个文件
//file = "c://a/1.png";
DWORD attr = GetFileAttributesW(StringUtf8ToWideChar(file).c_str());
if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
{
    cocos2d::log("file not exist");
}
else{
    cocos2d::log("file exist");
}
复制代码

为什么会出现search paths异常

FileUtils::getInstance()->addSearchPath("res");
void FileUtils::addSearchPath(const std::string &searchpath,const bool front)
{
    if (!isAbsolutePath(searchpath))
        prefix = _defaultResRootPath;
}
复制代码

当添加searchPaths的时候,如果是相对路径,则会追加_defaultResRootPath,而_defaultResRootPath在win32上的来源是ProjectConfig,在SimulatorWin::run中就会从命令行参数中解析workdir最终传递给_defaultResRootPath

void FileUtils::setDefaultResourceRootPath(const std::string& path)
{
    // 最主要的原因是这里缺少对path的校验
    if (_defaultResRootPath != path)
    {
        _fullPathCache.clear();
        _defaultResRootPath = path;
        if (!_defaultResRootPath.empty() && _defaultResRootPath[_defaultResRootPath.length()-1] != '/')
        {
            _defaultResRootPath += '/';
        }
        // Updates search paths
        setSearchPaths(_originalSearchPaths);
    }
}
复制代码

release出现问题就是因为args中缺少workdir

网络异常,图片无法展示
|
原始的win32项目填写了Command Arguments,所以规避了这个问题

结论

SearchPath的影响还是非常大的,写资源路径的时候,最好统一相对于一个目录写,不然cache中容易出现多份相同的资源。



目录
相关文章
|
存储 安全 Android开发
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表混淆 | resources.arsc 资源映射表二进制格式分析 | 混淆全局字符串池和资源名称字符串池 )
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表混淆 | resources.arsc 资源映射表二进制格式分析 | 混淆全局字符串池和资源名称字符串池 )
344 0
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表混淆 | resources.arsc 资源映射表二进制格式分析 | 混淆全局字符串池和资源名称字符串池 )
|
缓存 前端开发 JavaScript
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
104 0
|
缓存 监控 NoSQL
如何实现文件缓存?在项目中如何应用缓存技术提高性能?
如何实现文件缓存?在项目中如何应用缓存技术提高性能?
203 0
|
文件存储
Yii2.0框架提供了内置的文件访问组件,可以通过配置只允许访问指定的目录,防止非法文件的包含。这个如何使用?
Yii2.0框架提供了内置的文件访问组件,可以通过配置只允许访问指定的目录,防止非法文件的包含。这个如何使用?
114 0
|
存储 缓存 前端开发
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
|
存储 Web App开发 JavaScript
图解 Google V8 # 04:V8 中的对象表示:怎么利用 Chrome 内存快照去查看对象在内存中是如何布局的?
图解 Google V8 # 04:V8 中的对象表示:怎么利用 Chrome 内存快照去查看对象在内存中是如何布局的?
239 0
图解 Google V8 # 04:V8 中的对象表示:怎么利用 Chrome 内存快照去查看对象在内存中是如何布局的?
|
JavaScript
js如何拷贝元数据后,更改数据不对元数据有影响
js如何拷贝元数据后,更改数据不对元数据有影响
|
XML 缓存 NoSQL
分布式服务器框架之Server.Common中通过Xml配置渠道、服务器集群、热更新信息代码解析Xml缓存进内存
ChannelConfig.cs代码解析加载ChannelConfig.xml。使用了System.Xml.Linq的XDocument工具类来加载xml文件。其基本原理就是获取到Root节点下名为“Channel”的所有Element节点,然后使用迭代器循环,拿到每一个Element中的属性,先缓存ChannelEntity结构中,最后存到字典里。
|
前端开发 JavaScript PHP
Yii2 使用AssetBundle中的$sourcePath对资源文件进引入和调用
Yii2 使用AssetBundle中的$sourcePath对资源文件进引入和调用
212 0
|
Java 数据库连接 Spring
加载、读取资源的方式(底层都是以流的方式获取资源,具体是通过类加载器进行加载,通过流的方式进行读取,从而获取资源)
加载、读取资源的方式(底层都是以流的方式获取资源,具体是通过类加载器进行加载,通过流的方式进行读取,从而获取资源)
99 0