一 標記-清除演算法(Mark-Sweep)
首先標記出所有需要回收的物件,標記完成後統一回收。
主要缺點: 1. 標記和清除效率都很低 2. 產生大量不連續的記憶體碎片,導致後面分配大記憶體空間失敗
二 複製演算法
將可用記憶體劃分為大小相等的兩塊, 每次只使用其中一塊。 當這塊用完後,就將還存活物件複製到另外一塊上面,再把已經使用的記憶體空間一次清理掉。
主要缺點: 代價太高,至少一半的記憶體不能使用。
三 標記-整理演算法
標記過程和標記-清除演算法一致,但是後續步驟是讓所有存活的物件都向一端移動,然後清理掉邊界以外的記憶體。
四 分代收集演算法
當前商業虛擬機器都採用此演算法,分為不同物件代,去進行不同管理。【相關閱讀】
什麼是java位運算
位運算允許對整數中的單個位元進行操作。位運算會對連個運算元中對應的位元執行布林代數運算,併產生一個結果。
java中有3種位運算子:&(與) |(或) ^(異或) ~(非)
看例子說明位運算的過程:
public class test{
public static void main(String[] args){
int a=12|2; //1100|0010
tln(a);
}
}
結果是14(1110)
位移運算操作的目標也是數字的二進位制的位。用來操作位數的向左向右移動。
java種有3種基本的位移操作:
>>(右移) <<(左移)>>>(無符號右移)
<<:將操作符左邊的整數按位向左邊移動運算子右邊整數指定的位數,在右邊新增0;
看例子:
public class test{
public static void main(String[] args){
int a=8<<1;
tln(a);
}
}
8的二進位制表示:00000000 00000000 00000000 00001000
左移1位後二進位制:00000000 00000000 00000000 00010000 -> 14
結果為14
tip:左移相當於num*(2^n) 其中num為被移數,n為移動的位數
>>:右移的道理也是一樣的.,注意的是:若最高位為1,移動後最高位用1來填充,否則用0來填充。
例子:
int a=-8>>1;
tln(a);
-8的二進位制:11111111 11111111 11111111 11111000
右移後的二進位制:11111111 11111111 11111111 11111100 -> -4
結果為-4
tip:右移相當於num/(2^n) 其中num為被移數,n為移動的位數
>>>:無符號右移跟右移原理是一樣的,只是覆蓋位的覆蓋規則不同:不管最高位是0還是1,全部用0來填充。
例子:
int a=-8>>>1;
tln(a);
-8的二進位制:11111111 11111111 11111111 11111000
無符號右移後的二進位制:01111111 11111111 11111111 11111100 -> 2147483644
tip:用無符號右移的時候要注意,絕對值很小的負數移動後都可能成為絕對值很大的正數,這在大多數情況下沒意義。
奇葩的例外:
那程式碼:
int a=11>>32;
long b=12<<64;
tln(a);
tln(b);
int型別佔32位,long型別佔64位,這樣子的話,上面的例子輸出應該都是0才對,因為剛好將有效位都移走了,但結果並不是這樣的。
輸出的結果是:11 12
這跟java對位移的底層操作機制有關:
從結果可以看出兩個數都沒有變化,這是因為,在進行移位前,java首先將要移動的位數跟被移數的位數求餘,然後去移動餘數個位數。上面例子中,32對32求餘,64對64求餘,結果都是0,java系統對被移數進行0個位的移動,也就是沒
移動啦。
這樣子的話,看下下面的程式碼:
int c=8>>33;
tln(c);
因為int有32位,那麼8實際上被移動的位數是:332=1;
就相當於:int c=8>>1;
結果自然是:4