내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
메모리 스래싱(Memory Thrashing)은 짧은 시간 내에 많은 수의 객체가 생성되고 소멸되어 가비지 컬렉션(Garbage Collection, GC) 활동이 자주 발생하는 것을 말합니다. 이렇게 빈번한 GC 활동은 많은 CPU 리소스를 차지하며 애플리케이션 지연이나 성능 저하를 유발할 수 있습니다.
성능: 메모리 곡선이 들쭉날쭉합니다.
메모리 누수는 애플리케이션이 더 이상 필요하지 않은 개체에 대한 참조를 보유할 때 발생하며, 이로 인해 이러한 개체가 가비지 수집기에 의해 재활용되지 않아 해제될 수 있는 메모리 공간을 차지하게 됩니다. 시간이 지남에 따라 메모리 누수로 인해 사용 가능한 메모리가 점점 줄어들고 결국 애플리케이션 충돌이나 성능 저하로 이어질 수 있습니다.
메모리 오버플로는 애플리케이션이 더 많은 메모리 공간을 할당하려고 시도하지만 할당할 메모리 공간이 더 이상 부족하여 시스템이 요청을 충족할 수 없을 때 발생합니다. 이로 인해 일반적으로 응용 프로그램에서 OutOfMemoryError 예외가 발생합니다.
Java 메모리 구조: 힙, 가상 머신 스택, 메소드 영역, 프로그램 카운터, 로컬 메소드 스택.
Java 메모리 재활용 알고리즘:
표시 지우기 알고리즘의 단점: 표시 및 지우기가 효율적이지 않으며 많은 수의 불연속적인 메모리 조각이 생성됩니다.
복제 알고리즘: 구현이 간단하고 실행이 효율적입니다. 단점: 공간의 절반을 낭비했습니다.
Mark-compact 알고리즘: mark-clean으로 인한 메모리 조각화를 방지하고 복사 알고리즘의 공간 낭비를 방지합니다.
Android 메모리 탄력적 할당, 할당 값 및 최대 값은 특정 장치에 의해 영향을 받습니다.
Dalvik 재활용 알고리즘과 ART 재활용 알고리즘은 모두 Android 운영 체제에서 메모리 관리에 사용되는 가비지 수집 메커니즘입니다.
Dalvik 재활용 알고리즘:
미술품 재활용 알고리즘:
LMK 메커니즘:
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);
}
}
메모리 프로파일러에서 메모리 할당을 볼 수 있습니다. 'Record Java/Kotlin 할당'을 클릭하세요.
위의 의미:
다음과 같은 의미:
malloc()
또는new
운영자가 할당한 개체 수입니다.free()
또는delete
운영자가 할당을 취소한 개체 수입니다.위 그림의 분석:
이 영역의 Allocations 및 Deallocations 값은 비교적 유사하며 Shallow Size가 상대적으로 커서 개체가 자주 생성되고 소멸될 수 있음을 나타냅니다.
클릭 후 콜스택 정보를 확인할 수 있으며, 코드와 결합하여 핸들러에 메모리 지터 문제가 있음을 유추할 수 있습니다.
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() {
}
}
종속 라이브러리를 추가합니다.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
메모리 누수가 발생한 후 LeakCanary는 관련 정보를 생성하고 자동으로 덤프합니다.
위 그림에서 볼 수 있듯이 LeakActivity에 메모리 누수가 발생하고 참조 체인 관계가 표시됩니다.
물론 hprof 파일을 생성하고 프로파일러 도구를 통해 특정 정보를 볼 수도 있습니다.
위 그림에서 볼 수 있듯이 LeakActivity를 포함하여 10개의 누수 지점이 발생했습니다. LeakActivity를 클릭하면 메모리 누수 개체를 볼 수 있고 참조 체인을 확인하면 ArrayList에 의해 유지되는 것을 볼 수 있습니다.
Bitmap을 사용한 후 이미지 리소스를 해제하지 않으면 문제가 발생하기 쉽습니다.메모리 누수로 인해 메모리 오버플로가 발생함。
메모리 재활용:
Bitmap.recycle()
비트맵 재활용을 수행합니다.비트맵 픽셀 구성:
구성 | 점유 바이트 크기(바이트) | 설명하다 |
---|---|---|
알파_8 | 1 | 단일 투명 채널 |
RGB_565 | 2 | 간단한 RGB 색조 |
ARGB_8888 | 4 | 24비트 트루 컬러 |
RGBA_F16 | 8 | 안드로이드 8.0 신규(HDR) |
Btimap이 차지하는 메모리를 계산합니다.
리소스 파일 문제:
테스트 코드:
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
*/
설명하다:
mdpi 장치의 1dpxhdpi 장치의 경우 1px, 1dpxxhdpi 장치에서는 2px, 1dp==3px.
따라서 현재 장치는 xxhdpi이므로 xxhdpi 리소스 아래에서는 동일한 그림의 너비가 858이고, mdpi 리소스 아래에서는 3배로 확대되어 너비는 2574가 되며, xhdpi 리소스 아래에서는 1.5배로 확대되어 너비가 2574가 됩니다. 너비는 1287입니다.