【发布时间】:2016-07-10 19:11:39
【问题描述】:
我在 Android 上遇到了一些内存泄漏问题。
我确实有一个简单的应用程序,以相对图片作为背景,它工作正常,直到我改变方向。
下图显示了内存泄漏(随时间分配的内存)。每个尖峰对应一个方向变化,每个尖峰是 +20M 的分配内存
在大约 30 秒时,应用程序崩溃并出现明显的“OutOfMemory”错误:
抛出 OutOfMemoryError “无法分配 17469452 字节分配,804912 可用字节和 786KB 直到 OOM”`
布局只是一个简单的RelativeLayout,以jpeg图像作为背景
大小 ~ 430k
我也实现了onDestroy() 防内存泄漏解决方案(建议here):
@Override
protected void onDestroy()
{
unbindDrawables(view);
view = null;
System.gc();
super.onDestroy();
}
private void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
但它真的不会改变任何东西。
有什么办法可以解决这个问题吗? 我确实需要图片那么大,因为运行该应用的设备有一个大屏幕。
-- 编辑--
根据要求添加onCreate() 代码,
请注意,即使没有调用initMainView(),甚至有一个空的onCreate()(只有super),问题仍然存在,即使内存泄漏也很差(只有0.8M)但仍然存在。
我在 Pixel C 上运行 Android 6.0.1,如果这可能有帮助的话。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.gc();
w = getWindow();
w.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
dpm = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
deviceAdmin = new ComponentName(this, AdmRcvr.class);
if(!dpm.isDeviceOwnerApp(getPackageName())) {
setContentView(R.layout.deviceownertutorial);
final TextView tvTutorial = (TextView) w.findViewById(R.id.tutorialtv);
tvTutorial.setText(Html.fromHtml(getString(R.string.deviceownertutorial)));
final TextView tvDeviceOwnerError = (TextView) w.findViewById(R.id.tverrordeviceadmin);
Button checkDeviceAdmin = (Button) w.findViewById(R.id.cdevadmin);
checkDeviceAdmin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (dpm.isDeviceOwnerApp(getPackageName())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
setContentView(R.layout.startview);
initMainView();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvDeviceOwnerError.setText("App is not the device admin");
tvDeviceOwnerError.setVisibility(View.VISIBLE);
}
});
}
}
});
}
else
{
setContentView(R.layout.startview);
initMainView();
}
}
public void initMainView(){
// We're device owners!
View mDecorView = w.getDecorView();
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
mDecorView = null;
view = findViewById(R.id.sv_relativelayout);
initReader();
initBitmapCache();
enableTimer();
currentStep = 1;
}
--- 编辑 2 ---
在下图中,您可以看到两种情况下的内存分配:我的所有应用程序垃圾(如 430kB 图像)[a] 和没有(干净的onCreate())[b]。
请注意,如上所述,内存泄漏在这两种情况下仍然存在,即使它不是那么大(但确实存在!)。
该应用是针对 SDK v.23 和 buildToolsVersion 23.0.2 编译的。 依赖项如下:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.android.support:design:23.2.1'
}
app/libs 如下:
libs
└── acssmc-1.1.2.jar
--- 编辑 3 ---
使用新创建的应用程序进行测试时,内存按应有的方式进行管理,您可以在我的 GitHub repo 上看到一个示例
【问题讨论】:
-
你是使用普通的 Activity 还是 Activity 中的 Fragments?您能否也展示您的其他生命周期方法(尤其是 onCreate)?
-
如果显示更多代码会很有帮助。此外,您在 onDestroy() 中所做的事情并没有真正做任何事情,除非您的 Activity / Activity 的静态成员之外的东西正在引用您的视图,这无论如何都不会被您的 unbindDrawables() 解决。
-
按要求添加代码,希望对您有所帮助
-
什么是组件名?我看到您将“this”(即活动)传递给它。
-
ComponentName 用于设置 DevicePolicyManager.setLockTaskPackages() 然后,必须将应用程序上下文传递给新的 ComponentName。您发现了内存泄漏,现在我已使用 getApplicationContext() 进行了更正。但不幸的是,它并没有破坏应用程序。
标签: android performance memory memory-leaks