I'm having some troubles with memory leaks on Android.
I do have a simple application with a relatively picture as background and it works fine, until I change the orientation.
The following is a graph showing the memory leak (allocated memory over time). Every spike corresponds to an orientation change, and every spike is +20M of allocated memory
At ~ 30 seconds the app crashes with an obvious "OutOfMemory" error:
Throwing OutOfMemoryError "Failed to allocate a 17469452 byte allocation with 804912 free bytes and 786KB until OOM"`
The layout is just a simple RelativeLayout
with a jpeg image as background
sized ~ 430k
I do have implemented also an onDestroy()
anti-memory leak solution (as suggested 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();
}
}
But it really don't change anything.
Is there anything I can do to solve the issue? I do need the image to be that big because the device running the app has a big screen.
-- Edit --
Adding onCreate()
code as requested,
please do note that the problem is present even without calling initMainView()
and even by having an empty onCreate()
(with super only), even tough the memory leak is inferior (only 0.8M) but still present.
I'm running Android 6.0.1 on a Pixel C, if that might help.
@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;
}
--- EDIT 2 ---
In the following images you could see the memory allocation in two situation: with all my app garbage (like the 430kB image) [a] and without (a clean onCreate()
) [b].
Please do note that the memory leak is still present in both situation, as stated above, even tough it isn't that big (but there is!).
Memory leak, case [a]
Memory leak, case [b]
The app is compiled against SDK v.23 and with buildToolsVersion 23.0.2. The dependencies are the following:
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'
}
And the app/libs is the following:
libs
└── acssmc-1.1.2.jar
--- EDIT 3 ---
When testing with a newly created application the memory is managed as it should, you could see an example on my GitHub repo