谨慎使用android.view.SurfaceView.setVisibility方法
why?
原因就是此方法会导致native的内存暴增,前提条件你使用surfaceview去绘制一些复杂的3D图形,绘制复杂、业务复杂的场景;
setVisibility方法会调用surfaceView的updateSurface,而此方法内部就可能会分配大量的native内存
分析
/** @hide */
protected void updateSurface() {
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean visibleChanged = mVisible != mRequestedVisible;
final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
&& mRequestedVisible;
.....
if (creating) {
viewRoot.createBoundsSurface(mSubLayer);
mSurfaceSession = new SurfaceSession();
mDeferredDestroySurfaceControl = mSurfaceControl;
updateOpaqueFlag();
final String name = "SurfaceView - " + viewRoot.getTitle().toString();
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setName(name)
.setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
.setBufferSize(mSurfaceWidth, mSurfaceHeight)
.setFormat(mFormat)
.setParent(viewRoot.getSurfaceControl())
.setFlags(mSurfaceFlags)
.build();
mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
.setName("Background for -" + name)
.setOpaque(true)
.setColorLayer()
.setParent(mSurfaceControl)
.build();
} else if (mSurfaceControl == null) {
return;
}
.....
}
如上函数,重点在于满足creating为true的情况下new SurfaceControl.Builder,在这个builder里面,会直接创建SurfaceControl对象,在SurfaceControl构造方法中有一个:
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
SurfaceControl parent, SparseIntArray metadata){
mNativeObject = nativeCreate(session, name, w, h, format, flags,
parent != null ? parent.mNativeObject : 0, metaParcel);
}
nativeCreate是一个native方法,在native层的代码如下:
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
jobject metadataParcel) {
....
SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
sp<SurfaceControl> surface;
......
status_t err = client->createSurfaceChecked(
String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
.....
return reinterpret_cast<jlong>(surface.get());
}
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
PixelFormat format,
sp<SurfaceControl>* outSurface, uint32_t flags,
SurfaceControl* parent,
LayerMetadata metadata) {
sp<SurfaceControl> sur;
status_t err = mStatus;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IBinder> parentHandle;
sp<IGraphicBufferProducer> gbp;
if (parent != nullptr) {
parentHandle = parent->getHandle();
}
err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
&handle, &gbp);
.....
}
return err;
}
到这里就不继续往下分析,不过也不难看出就是要重新创建一个surface,上面的createSurfaceChecked方法中的“IGraphicBufferProducer”代码就是分配对应的图像内存的例证;所以从上surfaceView的setVisibility方法很有可能就在native层分配内存,如果频繁调用setVisibility方法,而又没做好回收工作,就极有可能使内存暴增,系统和应用奔溃,出现android.view.Surface$OutOfResourcesException异常
如果频繁setVisiviblity方法分配内存,系统会将当前surface对象之前分配的内存回收掉吗?
看了SurfaceView的updateSurface函数,里面有将之前创建的SurfaceControl回收掉,但是回收掉有一些列条件,比较复杂,我也没去深入的研究,有兴趣的可以自行去分析;
总结:在项目中如果没有存在内存泄露,而内存暴增又来源于native,可以参考是否来源于surfaceview;当然native也不仅限于此,还有其他的共享内存、自己代码的业务内存等,要多方面综合考虑
原文地址:https://blog.csdn.net/jackzhouyu/article/details/134730693
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_43966.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!