2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Memory jitter refers to the creation and destruction of a large number of objects in a short period of time, resulting in frequent garbage collection (GC) activities. This frequent GC activity will occupy a large amount of CPU resources and may cause application lag or performance degradation.
Symptom: The memory curve is jagged.
A memory leak is when an application holds references to objects that are no longer needed, preventing them from being reclaimed by the garbage collector, thus occupying memory that could have been freed. Over time, memory leaks can cause less and less available memory, which can eventually cause the application to crash or degrade performance.
Memory overflow means that the application tries to allocate more memory space, but the system cannot satisfy the request because there is not enough memory space to allocate. This usually causes the application to throw an OutOfMemoryError exception.
Java memory structure: heap, virtual machine stack, method area, program counter, local method stack.
Java memory recycling algorithm:
Disadvantages of the mark-and-sweep algorithm: The marking and sweeping efficiency is not high, and a large amount of discontinuous memory fragments will be generated.
Copy algorithm: simple to implement and efficient to run. Disadvantage: wastes half of the space.
Mark-sweep algorithm: avoids memory fragmentation caused by mark-sweep and avoids space waste caused by copy algorithms.
Android memory is flexibly allocated, and the allocated value and maximum value are affected by the specific device.
The Dalvik recycling algorithm and the ART recycling algorithm are both garbage collection mechanisms used for memory management in the Android operating system.
Dalvik recycling algorithm:
Art recycling algorithm:
LMK mechanism:
public class ShakeActivity extends AppCompatActivity {
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
String str = "";
for (int i = 0; i < 10000000; i++) {
str += i;
}
mHandler.sendEmptyMessageDelayed(1, 30);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shake);
}
public void startClick(View view) {
mHandler.sendEmptyMessage(1);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
}
Memory Profiler allows you to view memory allocations, click "Record Java/Kotlin allocations".
What this means:
The following means:
malloc()
ornew
The number of objects allocated by the operator.free()
ordelete
The number of objects deallocated by the operator.Analysis of the above picture:
The values of Allocations and Deallocations in this area are relatively close, and the Shallow Size is relatively large, indicating that objects may be created and destroyed frequently.
After clicking, you can view the call stack information. Combined with the code, it can be inferred that there is a memory jitter problem in the Handler.
public class CallbackManager {
public static ArrayList<Callback> sCallbacks = new ArrayList<>();
public static void addCallback(Callback callback) {
sCallbacks.add(callback);
}
public static void removeCallback(Callback callback) {
sCallbacks.remove(callback);
}
}
public class LeakActivity extends AppCompatActivity implements Callback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
ImageView imageView = findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
imageView.setImageBitmap(bitmap);
CallbackManager.addCallback(this);
}
@Override
public void onOperate() {
}
}
Add dependent libraries:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
When a memory leak occurs, LeakCanary will generate relevant information and automatically dump it:
As can be seen from the above figure: LeakActivity has a memory leak and shows the reference chain relationship.
Of course, you can also generate hprof files and view specific information through the Profiler tool:
As shown in the figure above, there are 10 leaks, including LeakActivity. Click LeakActivity to view the object of the memory leak and check the reference chain, which shows that it is held by ArrayList.
If you do not release the image resources after using the Bitmap, it is easy to causeMemory leaks, leading to memory overflow。
Memory Recycling:
Bitmap.recycle()
Recycle the Bitmap.Bitmap pixel configuration:
Config | Size in bytes (byte) | illustrate |
---|---|---|
ALPHA_8 | 1 | Single transparent channel |
RGB_565 | 2 | Easy RGB color tone |
ARGB_8888 | 4 | 24-bit true color |
RGBA_F16 | 8 | New in Android 8.0 (HDR) |
Calculate the memory occupied by Btimap:
Resource file problem:
Test code:
private void printBitmap(Bitmap bitmap, String drawable) {
String builder = drawable +
" Bitmap占用内存:" +
bitmap.getByteCount() +
" width:" +
bitmap.getWidth() +
" height:" +
bitmap.getHeight() +
" 1像素占用大小:" +
getByteBy1px(bitmap.getConfig());
Log.e("TAG", builder);
}
private int getByteBy1px(Bitmap.Config config) {
if (Bitmap.Config.ALPHA_8.equals(config)) {
return 1;
} else if (Bitmap.Config.RGB_565.equals(config)) {
return 2;
} else if (Bitmap.Config.ARGB_8888.equals(config)) {
return 4;
}
return 1;
}
// 逻辑密度
float density = metrics.density;
// 物理密度
int densityDpi = metrics.densityDpi;
Log.e("TAG", density + "-" + densityDpi);
// 1倍图
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.splash1);
printBitmap(bitmap1, "drawable-mdpi");
// 2倍图
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.splash2);
printBitmap(bitmap2, "drawable-xhdpi");
// 3倍图
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.splash3);
printBitmap(bitmap3, "drawable-xxhdpi");
// 4倍图
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.splash4);
printBitmap(bitmap4, "drawable-xxxhdpi");
// drawable
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
printBitmap(bitmap5, "drawable");
/*
3.0-480
drawable-mdpi Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
drawable-xhdpi Bitmap占用内存:9281844 width:1287 height:1803 1像素占用大小:4
drawable-xxhdpi Bitmap占用内存:4125264 width:858 height:1202 1像素占用大小:4
drawable-xxxhdpi Bitmap占用内存:2323552 width:644 height:902 1像素占用大小:4
drawable Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
*/
illustrate:
1dp on mdpi devices1px, 1dp on xhdpi devices2px, on xxhdpi devices 1dp==3px.
Therefore, the current device is xxhdpi, so the same picture is 858 wide in xxhdpi resources, 3 times wider in mdpi resources, and 1.5 times wider in xhdpi resources, which is 1287.