java的內存
棧區、堆區、靜態區/方法區
1、棧區:由編譯知器自動分配釋放,存放函數的參數值、局部變量的值等、基本類型的變量,例如int a=3中的a、對象的引用變量,例如Thread t=new Thread()中的t、具體方法執行結束之後,系統自動釋放JVM內存資源。
2、堆區:一般由程序員分配釋放,存放由new創建的對象和數組,jvm不定時道查看這個對象,如果沒有引用指向這個對象就內回收。
3、靜態區/方法區:存放全局變量,靜態變量和字符串常量,不釋放和整個應用的生命週期一樣。
堆內存和棧內存,兩者的區別?
-
引用變量是普通變量,定義時在棧內存中分配,引用變量在程序運行到作用域外後被釋放。而數組和對象本身在堆中分配,即使程序運行到使用new產生數組和對象的語句所在的代碼塊之外,數組和對象本身佔用的堆內存也不會被釋放。數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然佔着內存,在隨後的一個不確定的時間被垃圾回收器釋放掉,這個也是Java比較佔內存的主要原因。實際上,棧中的引用變量指向堆內存中的變量,這就是Java中的指針。
-
通俗來講,堆是用來存放對象的,而棧是用來執行程序的。
-
jvm只有一個堆區(heap),被所有線程共享;
每個線程包含一個棧區(stack),每個棧中的數據都是私有的,其他的棧不能訪問,但是同一個棧中變量是共享的;分爲3個部分:基本類型變量區,執行環境上下文,操作指令區。
爲什麼要有堆和棧?這樣設計有什麼好處?
- Java自動管理堆和棧,程序員不能直接地設置棧和堆。
- Java的堆是一個運行時數據區。堆是由JVM的垃圾回收器自動管理的。堆的優勢是可以在程序運行時,動態地分配內存
大小,但是正是由於這個原因,它的存取速度較慢。 - 棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小和生存期是必須確定的,缺乏靈活性。
棧有一個很重要的特性,就是存在棧中的數據可以共享。假設我們同時定義:
int a = 3;
int b = 3;
編譯器先處理int a = 3;首先它會在棧中創建一個變量爲a的引用,然後查找棧中是否有3這個值,如果沒找到,就將3存放進來,然後將a指向3。接着處理int b = 3;在創建完b的引用變量後,因爲在棧中已經有3這個值,便將b直接指向3。這樣,就出現了a與b同時均指向3的情況。這時,如果再令a=4;那麼編譯器會重新搜索棧中是否有4值,如果沒有,則將4存放進來,並令a指向4;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。要注意這種數據的共享與兩個對象的引用時
指向一個對象的這種共享是不同的,因爲這種情況a的修改並不會影響到b, 它是由編譯器完成的,它有利於節省空間。而一個對象引用變量修改了這個對象的內部狀態,會影響到另一個對象引用變量。
內存泄漏分析:
強引用
Object obj = new Object(); //只要obj還指向Object對象,Object對象就不會被回收
obj = null; //手動置null,幫助垃圾收集器回收此對象
單例的內存泄漏
單例的內存泄露 當Android想要釋放Activtity的時候 有單例(單例是static類型的 他的生命週期和整個程序一樣)使用了Activity的context導致單例無法釋放,推薦使用Application的Context
public class AppManager {
//有內存泄漏的問題:
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance == null) {
instance = new AppManager(context);
}
return instance;
}
}
內部類
非靜態內部類持有外部類實例的強引用。
如果我們在內部類創建一個靜態的實例,該實例的生命週期和程序一樣長,導致了該實例一直持有外部類的引用 導致該外部類的內存一直無法釋放。
class test{
private static final TAG = "";
}
解決方法:
1.將內部類更改爲靜態內部類
static class test{
private static final TAG = "";
}
2.避免靜態變量
匿名內部類
如果這個非靜態內部類實例內部執行耗時任務期間,Activity不幸被銷燬了,就會導致外圍對象不會被回收,從而導致內存泄漏
AsyncTask
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
while(true);
}
}.execute();
}
解決方法
private static class NimbleTask extends AsyncTask<Void, Void, Void> {
@Override protected Void doInBackground(Void... params) {
while(true);
}
}
void startAsyncTask() {
new NimbleTask().execute();
}
Handler
// 容易造成內存泄漏的寫法:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//...刷新頁面
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
解決方法
// 修復內存泄漏的方法:
private MyHandler mHandler = new MyHandler(this);
private TextView mTextView ;
private static class MyHandler extends Handler {
private WeakReference<Context> reference;
public MyHandler(Context context) {
reference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if(activity != null){
// activity.mTextView.setText("");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
Thread
void testThread() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
解決方法
private Thread thread;
@Override
public void onDestroy() {
super.onDestroy();
if (thread != null) {
thread.interrupt();
}
}
void spawnThread() {
thread = new Thread(new Runnable() {
@Override
public void run() {
while (!isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
bitmap資源未釋放
建議手動調用recycle()方法,釋放其Native內存:
if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
}