类的定义很简单,爆漏的接口也不是很多,只有7个并且都是static类型的,看来要打的不是一场硬仗
enum class GpuObjectType {
Texture = 0,
OffscreenBuffer,
Layer,
TypeCount,
};
class GpuMemoryTracker {
public:
GpuObjectType objectType() { return mType; }
int objectSize() { return mSize; }
static void onGLContextCreated();
static void onGLContextDestroyed();
static void dump();
static void dump(std::ostream& stream);
static int getInstanceCount(GpuObjectType type);
static int getTotalSize(GpuObjectType type);
static void onFrameCompleted();
protected:
GpuMemoryTracker(GpuObjectType type) : mType(type) {
ASSERT_GPU_THREAD();
startTrackingObject();
}
~GpuMemoryTracker() {
notifySizeChanged(0);
stopTrackingObject();
}
void notifySizeChanged(int newSize);
private:
void startTrackingObject();
void stopTrackingObject();
int mSize = 0;
GpuObjectType mType;
};
hwui中有三个类派生自GpuMemoryTracker类.
1 Layer类用于TextureView进行opengl渲染
2 Texture 纹理
3 OffscreenBuffer 是用来替代前边layer
关于hwui可以参考http://blog.csdn.net/jinzhuojun/article/details/54234354这篇文章
初始化之后都调用startTrackingObject会开启内存追踪
void GpuMemoryTracker::startTrackingObject() {
auto result = gObjectSet.insert(this);
LOG_ALWAYS_FATAL_IF(!result.second,
"startTrackingObject() on %p failed, already being tracked!", this);
gObjectStats[static_cast<int>(mType)].count++;
}
startTrackingObject是私有函数,进来之后直接添加this指针到gObjectSet维护的集合中,之后有给对应的统计信息计数加1
void GpuMemoryTracker::onGLContextCreated() {
LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? "
"current = %lu, gl thread = %lu", pthread_self(), gGpuThread);
gGpuThread = pthread_self();
}
void GpuMemoryTracker::onGLContextDestroyed() {
gGpuThread = 0;
if (CC_UNLIKELY(gObjectSet.size() > 0)) {
std::stringstream os;
dump(os);
ALOGE("%s", os.str().c_str());
LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
}
}
onGLContextCreated()函数在render thread创建时候记录下render线程id,销毁的时候如果还有没释放的内存,可能是出现内存泄漏了,打印一下调用栈. 记录线程id是为了检验创建GpuMemoryTracker子类在render thread中.
struct TypeStats {
int totalSize = 0;
int count = 0;
};
void GpuMemoryTracker::notifySizeChanged(int newSize) {
int delta = newSize - mSize;
mSize = newSize;
gObjectStats[static_cast<int>(mType)].totalSize += delta;
}
notifySizeChanged是统计gpu使用内存的关键函数,目前只有Texture实现了该函数,也就是目前只支持统计纹理数据的大小.将每一个类型的数据大小之和用gObjectStats保存.(gObjectStats中保存的元素都是TypeStats,所以既可以统计数量有可以统计内存占用)
还有个比较重要的函数就是在每帧绘制完成计算统计信息
void GpuMemoryTracker::onFrameCompleted() {
if (ATRACE_ENABLED()) {
char buf[128];
for (int type = 0; type < NUM_TYPES; type++) {
snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
const TypeStats& stats = gObjectStats[type];
ATRACE_INT(buf, stats.totalSize);
snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
ATRACE_INT(buf, stats.count);
}
}
std::vector<const Texture*> freeList;
for (const auto& obj : gObjectSet) {
if (obj->objectType() == GpuObjectType::Texture) {
const Texture* texture = static_cast<Texture*>(obj);
if (texture->cleanup) {
ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
texture->id(), texture->width(), texture->height());
freeList.push_back(texture);
}
}
}
for (auto& texture : freeList) {
const_cast<Texture*>(texture)->deleteTexture();
delete texture;
}
}
第一个for循环是给atrace的输出,输出每种类型的总大小和数量
第二个for循环就是清理那些无用的texture
最后最重要的函数就是给用户抓取信息的dump函数
void GpuMemoryTracker::dump(std::ostream& stream) {
for (int type = 0; type < NUM_TYPES; type++) {
const TypeStats& stats = gObjectStats[type];
stream << TYPE_NAMES[type];
stream << " is using " << SizePrinter{stats.totalSize};
stream << ", count = " << stats.count;
stream << std::endl;
} }
也是打印类型和总大小
是不是很简单,GpuMemoryTracker只是用于调试