<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Rising Sun

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      148 隨筆 :: 0 文章 :: 22 評(píng)論 :: 0 Trackbacks

    #

         摘要: 淺拷貝就比如像引用類型,而深拷貝就比如值類型。  淺拷貝是指源對(duì)象與拷貝對(duì)象共用一份實(shí)體,僅僅是引用的變量不同(名稱不同)。對(duì)其中任何一個(gè)對(duì)象的改動(dòng)都會(huì)影響另外一個(gè)對(duì)象。舉個(gè)例子,一個(gè)人一開始叫張三,后來改名叫李四了,可是還是同一個(gè)人,不管是張三缺胳膊少腿還是李四缺胳膊少腿,都是這個(gè)人倒霉。深拷貝是指源對(duì)象與拷貝對(duì)象互相獨(dú)立,其中任何一個(gè)對(duì)象的改動(dòng)都不會(huì)對(duì)另外一個(gè)對(duì)象造成影響。...  閱讀全文
    posted @ 2013-02-21 11:03 brock| 編輯 收藏

    Hashmap loadFactor設(shè)置初使化值的時(shí)候必須設(shè)置 loadFactor

    1、請(qǐng)查看 hashmap 如何初使化

     

    代碼:

     public HashMap(int initialCapacity, float loadFactor) {

            if (initialCapacity < 0)

                throw new IllegalArgumentException("Illegal initial capacity: " +

                                                   initialCapacity);

            if (initialCapacity > MAXIMUM_CAPACITY)

                initialCapacity = MAXIMUM_CAPACITY;

            if (loadFactor <= 0 || Float.isNaN(loadFactor))

                throw new IllegalArgumentException("Illegal load factor: " +

                                                   loadFactor);

     

            // Find a power of 2 >= initialCapacity

            int capacity = 1;

            while (capacity < initialCapacity)

                capacity <<= 1;

     

            this.loadFactor = loadFactor;

            threshold = (int)(capacity * loadFactor);

            table = new Entry[capacity];

            init();

    }

     

    當(dāng)

    Map map = new HashMap(9);

     

    while (capacity < initialCapacity)

                capacity <<= 1;

     

    capacity的容量為 16

    threshold擴(kuò)容閥值 16*0.75 =12

     

    和9沒什么關(guān)系 哈

     

    當(dāng)

    Map map = new HashMap(91);

     

    capacity的容量為 16

    threshold擴(kuò)容閥值 16*1 =16
    不過這個(gè) 9 變小一點(diǎn) 就不一樣了 如3時(shí)
    capacity 是4



     

    posted @ 2013-02-01 16:37 brock 閱讀(2922) | 評(píng)論 (0)編輯 收藏


    學(xué)了這么久的Java,才知道Java的對(duì)象引用類型有4種。所以,趕緊把不知道的東西補(bǔ)上!

        對(duì)于需要長(zhǎng)期運(yùn)行的應(yīng)用程序來說,如果無用的對(duì)象所占用的內(nèi)存空間不能得到即時(shí)的釋放的話,那么在一個(gè)局部的時(shí)間段內(nèi)便形成了事實(shí)上的內(nèi)存泄露。

        以前我們學(xué)過,如果要及時(shí)地釋放內(nèi)存,最穩(wěn)妥的方法就是使用完對(duì)象之后,立刻執(zhí)行"object=null"語句。當(dāng)然,這也是一種理想狀態(tài)。

        JDK里面引入了4種對(duì)象引用類型,可以算是強(qiáng)行的調(diào)用System.gc()這個(gè)的垃圾回收的方法了。

       

        強(qiáng)引用:前面我們用的全部對(duì)象都是強(qiáng)引用類型的。這個(gè)就顯示地執(zhí)行"object=null"語句。

        軟引用:被軟引用的對(duì)象,如果內(nèi)存空間足夠,垃圾回收器是不會(huì)回收它的,如果內(nèi)存空間不足,垃圾回收器將回收這些對(duì)象占用的內(nèi)存空間。軟件引用對(duì)應(yīng)著java.lang.ref.SoftReference類,一個(gè)對(duì)象如果要被軟引用,只需將其作為參數(shù)傳入SoftReference類的構(gòu)造方法中就行了。感覺還是比較簡(jiǎn)單而且容易理解。

        弱引用:與前面的軟引用相比,被弱引用了的對(duì)象擁有更短的內(nèi)存時(shí)間(也就是生命周期)。垃圾回收器一旦發(fā)現(xiàn)了被弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間是不是足夠,都會(huì)回收它的內(nèi)存,弱引用對(duì)應(yīng)著java.lang.ref.WeakReference類,同樣的道理。一個(gè)對(duì)象如果想被弱引用,只需將其作為參數(shù)傳入WeakReference類的構(gòu)造方法中就行了。

        虛引用:虛引用不是一種真實(shí)可用的引用類型,完全可以視為一種“形同虛設(shè)”的引用類型。設(shè)計(jì)虛引用的目的在于結(jié)合引用關(guān)聯(lián)隊(duì)列,實(shí)現(xiàn)對(duì)對(duì)象引用關(guān)系的跟蹤(太高科技了,這幾句話。目前還不知道是什么意思)。虛引用對(duì)應(yīng)著java.lang.ref.PhantomReference類。一個(gè)對(duì)象如果要被虛引用,只需將其作為參數(shù)傳入PhantomReference類的構(gòu)造方法中就行了,同時(shí)作為參數(shù)傳入的還有引用關(guān)聯(lián)隊(duì)列java.lang.ref.ReferenceQueue的對(duì)象實(shí)例。(沒懂)

        SoftReference,WeakReference,PhantomReference類都繼承自java.lang.ref.Reference抽象類。Reference抽象類定義了clear() 方法用于撤銷引用關(guān)系,get()方法用于返回被引用的對(duì)象。

        摘抄一段代碼示例:

    import java.lang.ref.SoftReference;
    import java.lang.ref.WeakReference;
    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    import java.util.Set;
    import java.util.HashSet;

    public class TestReferences
    {
        public static void main(String[] args)
        {
            int length=10;
           
            //創(chuàng)建length個(gè)MyObject對(duì)象的強(qiáng)引用
            Set<MyObject> a = new HashSet<MyObject>();
            for(int i = 0; i < length; i++)
            {
                MyObject ref=new MyObject("Hard_" + i);
                System.out.println("創(chuàng)建強(qiáng)引用:" +ref);
                a.add(ref);
            }
            //a=null;
            System.gc();
           
            //創(chuàng)建length個(gè)MyObject對(duì)象的軟引用
            Set<SoftReference<MyObject>> sa = new HashSet<SoftReference<MyObject>>();
            for(int i = 0; i < length; i++)
            {
                SoftReference<MyObject> ref=new SoftReference<MyObject>(new MyObject("Soft_" + i));
                System.out.println("創(chuàng)建軟引用:" +ref.get());
                sa.add(ref);
            }
            System.gc();

            //創(chuàng)建length個(gè)MyObject對(duì)象的弱引用
            Set<WeakReference<MyObject>> wa = new HashSet<WeakReference<MyObject>>();
            for(int i = 0; i < length; i++)
            {
                WeakReference<MyObject> ref=new WeakReference<MyObject>(new MyObject("Weak_" + i));
                System.out.println("創(chuàng)建弱引用:" +ref.get());
                wa.add(ref);
            }
            System.gc();

            //創(chuàng)建length個(gè)MyObject對(duì)象的虛引用
            ReferenceQueue<MyObject> rq = new ReferenceQueue<MyObject>();
            Set<PhantomReference<MyObject>> pa = new HashSet<PhantomReference<MyObject>>();
            for(int i = 0; i < length; i++)
            {
                PhantomReference<MyObject> ref = new PhantomReference<MyObject>(new MyObject("Phantom_" + i), rq);
                System.out.println("創(chuàng)建虛引用:" +ref.get());
                pa.add(ref);
            }
            System.gc();
        }
    }

    class MyObject
    {
        private String id;

        public MyObject(String id)
        {
            this.id = id;
        }

        public String toString()
        {
            return id;
        }

        public void finalize()
        {
            System.out.println("回收對(duì)象:" + id);
        }
    }

     

    posted @ 2013-01-21 16:40 brock 閱讀(257) | 評(píng)論 (0)編輯 收藏

    一直在學(xué)習(xí)Java,碰到了很多問題,碰到了很多關(guān)于i++和++i的難題,以及最經(jīng)典的String str = "abc" 共創(chuàng)建了幾個(gè)對(duì)象的疑難雜癥。 知道有一日知道了java的反匯編 命令 javap。現(xiàn)將學(xué)習(xí)記錄做一小結(jié),以供自己以后翻看。如果有錯(cuò)誤的地方,請(qǐng)指正

    1.javap是什么:

    where options include:
    -c Disassemble the code
    -classpath <pathlist> Specify where to find user class files
    -extdirs <dirs> Override location of installed extensions
    -help Print this usage message
    -J<flag> Pass <flag> directly to the runtime system
    -l Print line number and local variable tables
    -public Show only public classes and members
    -protected Show protected/public classes and members
    -package Show package/protected/public classes
    and members (default)
    -private Show all classes and members
    -s Print internal type signatures
    -bootclasspath <pathlist> Override location of class files loaded
    by the bootstrap class loader
    -verbose Print stack size, number of locals and args for met
    hods
    If verifying, print reasons for failure 

    以上為百度百科里對(duì)它的描述,只是介紹了javap的一些參數(shù)和使用方法,而我們要用的就是這一個(gè):-c Disassemble the code。

    明確一個(gè)問題:javap是什么?網(wǎng)上有人稱之為 反匯編器,可以查看java編譯器為我們生成的字節(jié)碼。通過它,我們可以對(duì)照源代碼和字節(jié)碼,從而了解很多編譯器內(nèi)部的工作。

    2.初步認(rèn)識(shí)javap

    從一個(gè)最簡(jiǎn)單的例子開始:

    這個(gè)例子中,我們只是簡(jiǎn)單的聲明了兩個(gè)int型變量并賦上初值。下面我們看看javap給我們帶來了什么:(當(dāng)然執(zhí)行javap命令前,你得首先配置好自己的環(huán)境,能用javac編譯通過了,即:javac TestJavap.java )

    我們只看(方便起見,將注釋寫到每句后面)

    Code:
    0: iconst_2
     //把2放到棧頂
    1: istore_1 //把棧頂?shù)闹捣诺骄植孔兞?中,即i中
    2: iconst_3 //把3放到棧頂
    3: istore_2 //把棧頂?shù)闹捣诺骄植孔兞?中,即j中
    4: return

    是不是很簡(jiǎn)單?(當(dāng)然,估計(jì)需要點(diǎn)數(shù)據(jù)結(jié)構(gòu)的知識(shí)) ,那我們就補(bǔ)點(diǎn)java的關(guān)于堆棧的知識(shí):

    對(duì)于 int i = 2;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為i的引用,然后查找有沒有字面值為2的地址,沒找到,就開辟一個(gè)存放2這個(gè)字面值的地址,然后將i指向2的地址。

    看了這段話,再比較下上面的注釋,是不是完全吻合?

    為了驗(yàn)證上面這一說法,我們繼續(xù)實(shí)驗(yàn):

    我們將 i 和 j的值都設(shè)為2。按照以上理論,在聲明j的時(shí)候,會(huì)去棧中招有沒有字面值為2的地址,由于在棧中已經(jīng)有2這個(gè)字面值,便將j直接指向2的地址。這樣,就出現(xiàn)了i與j同時(shí)均指向2的情況。

    拿出javap -c進(jìn)行反編譯:結(jié)果如下:

    Code:
    0: iconst_2 //把2放到棧頂
    1: istore_1 //把棧頂?shù)闹捣诺骄植孔兞?中,即i中
    2: iconst_2 //把2放到棧頂
    3: istore_2 //把棧頂?shù)闹捣诺骄植孔兞?中,即j中(i 和 j同時(shí)指向2)
    4: return

    雖然這里說i和j同時(shí)指向2,但這里不等于說i和j指向同一塊地址(java是不允許程序員直接修改堆棧中的數(shù)據(jù)的,所以就不要想著,我是不是可以修改棧中的2,那樣豈不是i和j的值都會(huì)變化。另:在編譯器內(nèi)部,遇到j(luò)=2;時(shí),它就會(huì)重新搜索棧中是否有2的字面值,如果沒有,重新開辟地址存放2的值;如果已經(jīng)有了,則直接將j指向這個(gè)地址。因此,就算j另被賦值為其他值,如j=4,j值的改變不會(huì)影響到i的值。)

    再來一個(gè)例子:

    還是javap -c

    Code:
    0: iconst_2 //把2放到棧頂
    1: istore_1 //把棧頂?shù)闹捣诺骄植孔兞?中,即i中
    2: iload_1 //把i的值放到棧頂,也就是說此時(shí)棧頂?shù)闹凳?
    3: istore_2 //把棧頂?shù)闹捣诺骄植孔兞?中,即j中
    4: return

    看到這里是不是有點(diǎn)明確了?

     

     

    既然我們對(duì)javap有了一定的了解,那我們就開始用它來解決一些實(shí)際的問題:

    1.i++和++i的問題

    反編譯結(jié)果為

    Code:
    0: iconst_1
    1: istore_1
    2: iinc 1, 1 //這個(gè)個(gè)指令,把局部變量1,也就是i,增加1,這個(gè)指令不會(huì)導(dǎo)致棧的變化,i此時(shí)變成2了
    5: iconst_1
    6: istore_2
    7: iinc 2, 1//這個(gè)個(gè)指令,把局部變量2,也就是j,增加1,這個(gè)指令不會(huì)導(dǎo)致棧的變化,j此時(shí)變成2了
    10: return

    可以看出,++在前在后,在這段代碼中,沒有任何不同。

    我們?cè)倏戳硪欢未a:

    反編譯結(jié)果:

    Code:
    0: iconst_1
    1: istore_1
    2: iload_1
    3: iinc 1, 1 //局部變量1(即i)加1變?yōu)?,注意這時(shí)棧中仍然是1,沒有改變
    6: istore_1 //把棧頂?shù)闹捣诺骄植孔兞?中,即i這時(shí)候由2變成了1
    7: iconst_1
    8: istore_2
    9: iinc 2, 1 //局部變量2(即j)加1變?yōu)?,注意這時(shí)棧中仍然是1,沒有改變
    12: iload_2 //把局部變量2(即j)的值放到棧頂,此時(shí)棧頂?shù)闹底優(yōu)?
    13: istore_2 //把棧頂?shù)闹捣诺骄植孔兞?中,即j這時(shí)候真正由1變成了2
    14: return

    是否看明白了? 如果這個(gè)看明白了,那么下面的一個(gè)問題應(yīng)該就是迎刃而解了:

    m = m ++;這句話,java虛擬機(jī)執(zhí)行時(shí)是這樣的: m的值加了1,但這是棧中的值還是0, 馬上棧中的值覆蓋了m,即m變成0,因此不管循環(huán)多少次,m都等于0。

    如果改為m = ++m; 程序運(yùn)行結(jié)果就是100了。。。

     

     

    posted @ 2013-01-21 15:26 brock 閱讀(368) | 評(píng)論 (1)編輯 收藏

    public static void main(String[] args) {
    Calendar c = Calendar.getInstance();
    System.out.println(c.get(Calendar.YEAR) * 100 + c.get(Calendar.WEEK_OF_YEAR));
    c.set(Calendar.YEAR, 2013);
    c.set(Calendar.WEEK_OF_YEAR, c.get(Calendar.WEEK_OF_YEAR));
    int w = c.get(Calendar.DAY_OF_WEEK);
    for (int i = 1; i <= 7; i++) {
    c.set(Calendar.DAY_OF_WEEK, i);
    System.out.println("該周第一天是[" + DateFormatUtils.format(c, "yyyy-MM-dd") + "]");
    }
    int dd = 201205;
    System.out.println(dd / 100);
    System.out.println(dd % (dd / 100));
    }
    posted @ 2013-01-10 10:56 brock 閱讀(190) | 評(píng)論 (0)編輯 收藏

    public static void main(String[] args) {
    List<Integer> a = new ArrayList<Integer>();
    a.add(1);
    a.add(5);
    a.add(7);
    a.add(9);
    List<Integer> b = new ArrayList<Integer>();
    b.add(2);
    b.add(4);
    b.add(8);
    List<Integer> c = new ArrayList<Integer>();
    c.addAll(a);
    c.addAll(b);
    List<Integer> d = new ArrayList<Integer>();
    for (Integer dd : b) {
    d.add(dd);
    }
    // Integer
    Collections.sort(c, new Comparator<Integer>() {
    @Override
    public int compare(Integer source, Integer desc) {
    if (source.compareTo(desc) > 0) {
    return 1;
    }
    return -1;
    }
    });
    for (int j = 0; j < a.size(); j++) {
    for (int k = 0; k < b.size(); k++) {
    if (a.get(j) > b.get(k)) {
    if (k == b.size() - 1) {
    b.add(b.get(b.size() - 1));
    break;
    }
    continue;
    }
    //
    if (a.get(j) < b.get(k)) {
    if (k == 0) {
    b.add(k, 0);
    } else {
    b.add(k, b.get(k - 1));
    }
    break;
    }
    }
    }
    for (int j = 0; j < d.size(); j++) {
    for (int k = 0; k < a.size(); k++) {
    if (d.get(j) > a.get(k)) {
    if (k == a.size() - 1) {
    a.add(a.get(a.size() - 1));
    break;
    }
    continue;
    }
    //
    if (d.get(j) < a.get(k)) {
    if (k == 0) {
    a.add(k, 0);
    } else {
    a.add(k, a.get(k - 1));
    }
    break;
    }
    }
    }
    System.out.println(c);
    System.out.println(a);
    System.out.println(b);
    }
    posted @ 2013-01-07 15:13 brock 閱讀(307) | 評(píng)論 (0)編輯 收藏

    Java.Lang.NoSuchMethodError:仔細(xì)檢查,原來我自己將tomcat下的lib也導(dǎo)入進(jìn)來了,里面有一個(gè)commons-collection.jar(2.0版本),暈啊!馬上砍掉,導(dǎo)入commons-collection.jar 3.0版本,一切OK,郁悶了一個(gè)晚上!!!! 
    he.Commons.Collections
     
    posted @ 2012-10-10 10:15 brock 閱讀(282) | 評(píng)論 (0)編輯 收藏

        首先感謝阿寶同學(xué)的幫助,我才對(duì)這個(gè)gc算法的調(diào)整有了一定的認(rèn)識(shí),而不是停留在過去僅僅了解的階段。在讀過sun的文檔和跟阿寶討論之后,做個(gè)小小的總結(jié),如果有謬誤,敬請(qǐng)指正。
        CMS,全稱Concurrent Low Pause Collector,是jdk1.4后期版本開始引入的新gc算法,在jdk5和jdk6中得到了進(jìn)一步改進(jìn),它的主要適合場(chǎng)景是對(duì)響應(yīng)時(shí)間的重要性需求 大于對(duì)吞吐量的要求,能夠承受垃圾回收線程和應(yīng)用線程共享處理器資源,并且應(yīng)用中存在比較多的長(zhǎng)生命周期的對(duì)象的應(yīng)用。CMS是用于對(duì)tenured generation的回收,也就是年老代的回收,目標(biāo)是盡量減少應(yīng)用的暫停時(shí)間,減少full gc發(fā)生的幾率,利用和應(yīng)用程序線程并發(fā)的垃圾回收線程來標(biāo)記清除年老代。在我們的應(yīng)用中,因?yàn)橛芯彺娴拇嬖冢⑶覍?duì)于響應(yīng)時(shí)間也有比較高的要求,因此希 望能嘗試使用CMS來替代默認(rèn)的server型JVM使用的并行收集器,以便獲得更短的垃圾回收的暫停時(shí)間,提高程序的響應(yīng)性。
        CMS并非沒有暫停,而是用兩次短暫停來替代串行標(biāo)記整理算法的長(zhǎng)暫停,它的收集周期是這樣:
        初始標(biāo)記(CMS-initial-mark) -> 并發(fā)標(biāo)記(CMS-concurrent-mark) -> 重新標(biāo)記(CMS-remark) -> 并發(fā)清除(CMS-concurrent-sweep) ->并發(fā)重設(shè)狀態(tài)等待下次CMS的觸發(fā)(CMS-concurrent-reset)
        其中的1,3兩個(gè)步驟需要暫停所有的應(yīng)用程序線程的。第一次暫停從root對(duì)象開始標(biāo)記存活的對(duì)象,這個(gè)階段稱為初始標(biāo)記;第二次暫停是在并發(fā)標(biāo)記之后, 暫停所有應(yīng)用程序線程,重新標(biāo)記并發(fā)標(biāo)記階段遺漏的對(duì)象(在并發(fā)標(biāo)記階段結(jié)束后對(duì)象狀態(tài)的更新導(dǎo)致)。第一次暫停會(huì)比較短,第二次暫停通常會(huì)比較長(zhǎng),并且 remark這個(gè)階段可以并行標(biāo)記。

        而并發(fā)標(biāo)記、并發(fā)清除、并發(fā)重設(shè)階段的所謂并發(fā),是指一個(gè)或者多個(gè)垃圾回收線程和應(yīng)用程序線程并發(fā)地運(yùn)行,垃圾回收線程不會(huì)暫停應(yīng)用程序的執(zhí)行,如果你有多于一個(gè)處理器,那么并發(fā)收集線程將與應(yīng)用線程在不同的處理器上運(yùn)行,顯然,這樣的開銷就是會(huì)降低應(yīng)用的吞吐量。Remark階段的并行,是指暫停了所有應(yīng)用程序后,啟動(dòng)一定數(shù)目的垃圾回收進(jìn)程進(jìn)行并行標(biāo)記,此時(shí)的應(yīng)用線程是暫停的。

        CMS的young generation的回收采用的仍然是并行復(fù)制收集器,這個(gè)跟Paralle gc算法是一致的。

        下面是參數(shù)介紹和遇到的問題總結(jié),

    1、啟用CMS:-XX:+UseConcMarkSweepGC。 咳咳,這里犯過一個(gè)低級(jí)錯(cuò)誤,竟然將+號(hào)寫成了-號(hào)

     

    2。CMS默認(rèn)啟動(dòng)的回收線程數(shù)目是  (ParallelGCThreads + 3)/4) ,如果你需要明確設(shè)定,可以通過-XX:ParallelCMSThreads=20來設(shè)定,其中ParallelGCThreads是年輕代的并行收集線程數(shù)


    3、CMS是不會(huì)整理堆碎片的,因此為了防止堆碎片引起full gc,通過會(huì)開啟CMS階段進(jìn)行合并碎片選項(xiàng):-XX:+UseCMSCompactAtFullCollection,開啟這個(gè)選項(xiàng)一定程度上會(huì)影響性能,阿寶的blog里說也許可以通過配置適當(dāng)?shù)腃MSFullGCsBeforeCompaction來調(diào)整性能,未實(shí)踐。

    4.為了減少第二次暫停的時(shí)間,開啟并行remark: -XX:+CMSParallelRemarkEnabled。如果remark還是過長(zhǎng)的話,可以開啟-XX:+CMSScavengeBeforeRemark選項(xiàng),強(qiáng)制remark之前開始一次minor gc,減少remark的暫停時(shí)間,但是在remark之后也將立即開始又一次minor gc。

    5.為了避免Perm區(qū)滿引起的full gc,建議開啟CMS回收Perm區(qū)選項(xiàng):

    +CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled


    6.默認(rèn)CMS是在tenured generation沾滿68%的時(shí)候開始進(jìn)行CMS收集,如果你的年老代增長(zhǎng)不是那么快,并且希望降低CMS次數(shù)的話,可以適當(dāng)調(diào)高此值:
    -XX:CMSInitiatingOccupancyFraction=80

    這里修改成80%沾滿的時(shí)候才開始CMS回收。

    7.年輕代的并行收集線程數(shù)默認(rèn)是(cpu <= 8) ? cpu : 3 + ((cpu * 5) / 8),如果你希望降低這個(gè)線程數(shù),可以通過-XX:ParallelGCThreads= N 來調(diào)整。

    8.進(jìn)入重點(diǎn),在初步設(shè)置了一些參數(shù)后,例如:

     

    Java代碼  收藏代碼
    1. -server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m  
    2. -XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection  
    3. -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled  
    4. -XX:SoftRefLRUPolicyMSPerMB=0  

     

    需要在生產(chǎn)環(huán)境或者壓測(cè)環(huán)境中測(cè)量這些參數(shù)下系統(tǒng)的表現(xiàn),這時(shí)候需要打開GC日志查看具體的信息,因此加上參數(shù):

    -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/test/logs/gc.log

    在運(yùn)行相當(dāng)長(zhǎng)一段時(shí)間內(nèi)查看CMS的表現(xiàn)情況,CMS的日志輸出類似這樣:

     

    Java代碼  收藏代碼
    1. 4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs]  
    2. 4391.352: [CMS-concurrent-mark-start]  
    3. 4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs]  
    4. 4391.779: [CMS-concurrent-preclean-start]  
    5. 4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs]  
    6. 4391.821: [CMS-concurrent-abortable-preclean-start]  
    7. 4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs]  
    8. 4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs]  
    9. 4392.609: [CMS-concurrent-sweep-start]  
    10. 4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs]  
    11. 4394.310: [CMS-concurrent-reset-start]  
    12. 4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs]  
     


    其中可以看到CMS-initial-mark階段暫停了0.0303050秒,而CMS-remark階段暫停了0.0932010秒,因此兩次暫停的總共時(shí)間是0.123506秒,也就是123毫秒左右。兩次短暫停的時(shí)間之和在200以下可以稱為正常現(xiàn)象。

    但是你很可能遇到兩種fail引起full gc:Prommotion failed和Concurrent mode failed。

    Prommotion failed的日志輸出大概是這樣:

     

    Java代碼  收藏代碼
    1. [ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K(  
    2. 166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]  


    這個(gè)問題的產(chǎn)生是由于救助空間不夠,從而向年老代轉(zhuǎn)移對(duì)象,年老代沒有足夠的空間來容納這些對(duì)象,導(dǎo)致一次full gc的產(chǎn)生。解決這個(gè)問題的辦法有兩種完全相反的傾向:增大救助空間、增大年老代或者去掉救助空間。 增大救助空間就是調(diào)整-XX:SurvivorRatio參數(shù),這個(gè)參數(shù)是Eden區(qū)和Survivor區(qū)的大小比值,默認(rèn)是32,也就是說Eden區(qū)是 Survivor區(qū)的32倍大小,要注意Survivo是有兩個(gè)區(qū)的,因此Surivivor其實(shí)占整個(gè)young genertation的1/34。調(diào)小這個(gè)參數(shù)將增大survivor區(qū),讓對(duì)象盡量在survitor區(qū)呆長(zhǎng)一點(diǎn),減少進(jìn)入年老代的對(duì)象。去掉救助空 間的想法是讓大部分不能馬上回收的數(shù)據(jù)盡快進(jìn)入年老代,加快年老代的回收頻率,減少年老代暴漲的可能性,這個(gè)是通過將-XX:SurvivorRatio 設(shè)置成比較大的值(比如65536)來做到。在我們的應(yīng)用中,將young generation設(shè)置成256M,這個(gè)值相對(duì)來說比較大了,而救助空間設(shè)置成默認(rèn)大小(1/34),從壓測(cè)情況來看,沒有出現(xiàn)prommotion failed的現(xiàn)象,年輕代比較大,從GC日志來看,minor gc的時(shí)間也在5-20毫秒內(nèi),還可以接受,因此暫不調(diào)整。

    Concurrent mode failed的產(chǎn)生是由于CMS回收年老代的速度太慢,導(dǎo)致年老代在CMS完成前就被沾滿,引起full gc,避免這個(gè)現(xiàn)象的產(chǎn)生就是調(diào)小-XX:CMSInitiatingOccupancyFraction參數(shù)的值,讓CMS更早更頻繁的觸發(fā),降低年老代被沾滿的可能。我們的應(yīng)用暫時(shí)負(fù)載比較低,在生產(chǎn)環(huán)境上年老代的增長(zhǎng)非常緩慢,因此暫時(shí)設(shè)置此參數(shù)為80。在壓測(cè)環(huán)境下,這個(gè)參數(shù)的表現(xiàn)還可以,沒有出現(xiàn)過Concurrent mode failed。


    參考資料:
    》 by 江南白衣
    《記一次Java GC調(diào)整經(jīng)歷》
    1,2 by Arbow
    Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
    Tuning Garbage Collection with the 5.0 JavaTM Virtual Machine

    posted @ 2012-09-12 12:59 brock 閱讀(1184) | 評(píng)論 (1)編輯 收藏

    導(dǎo)航

    Linux vim編輯命令總結(jié)

    Posted on 2011-11-20 22:42 Biffo Lee 閱讀(685) 評(píng)論(0編輯 收藏 

    1.     啟動(dòng)vim編譯器

    vim filename                     打開原有的文件或創(chuàng)建一個(gè)新文件。

    vim                                  打開一個(gè)新文件,在編輯過程中或結(jié)束編輯時(shí)再指定文件名。

    vim –r filename                恢復(fù)因意外停機(jī)或終端連接中斷而未及時(shí)保存最終編輯結(jié)果的文件。

    view filename                   以只讀方式打開文件。除了不能把編輯處理的最終結(jié)果寫入文件保存之外,view的所有編輯功能均與vim無異。

    2.     光標(biāo)定位命令

    ←↑↓→                        將光標(biāo)左移、上移、下移或右移一個(gè)字符(行)位置。

    h j k l                              同上。

    -                                     光標(biāo)上移一行。

    Enter鍵(或加號(hào)“+”)光標(biāo)下移一行。

    退格鍵                            將光標(biāo)左移一個(gè)字符位置。

    空格鍵                            將光標(biāo)右移一個(gè)字符位置(命令模式)。

    Ctrl+F                             往下(文件結(jié)尾方向)滾動(dòng)一屏。

    Ctrl+B                             往上(文件開始方向)滾動(dòng)一屏。

    Ctrl+D                             往下滾動(dòng)半屏。

    Ctrl+U                             往上滾動(dòng)半屏。

    Ctrl+E                             編輯窗口中的文件內(nèi)容整體上移一行。

    Ctrl+Y                             編輯窗口中的文件內(nèi)容整體下移一行。

    w                                     將光標(biāo)右移一個(gè)字。光標(biāo)停留在下一個(gè)字的字首位置。

    W                                    將光標(biāo)右移一個(gè)字。光標(biāo)停留在下一個(gè)字的字首位置(即使兩個(gè)字之間存在標(biāo)點(diǎn)符號(hào))。

    b                                     將光標(biāo)左移一個(gè)字。光標(biāo)停留在下一個(gè)字的字首位置。

    B                                     將光標(biāo)左移一個(gè)字。光標(biāo)停留在下一個(gè)字的字首位置(即使兩個(gè)字之間存在標(biāo)點(diǎn)符號(hào))。

    e                                      把光標(biāo)移至當(dāng)前所在字(或下一個(gè)字)的最后一個(gè)字符位置。

    E                                     同上,只是以空格字符作為字的分隔符。

    ^                                      把光標(biāo)移至當(dāng)前行的起始位置,也即當(dāng)前行的第一個(gè)非空白字符位置

    0(零)                           同上

    $                                      把光標(biāo)移至當(dāng)前行的行尾,也即當(dāng)前行的最后一個(gè)字符位置。

    H                                     把光標(biāo)移至編輯窗口頂部第一行的行首位置。

    M                                    把光標(biāo)移至編輯窗口中間一行的行首位置。

    L                                     把光標(biāo)移至編輯窗口底部最后一行的行首位置。

    3.     插入文本數(shù)據(jù)

    a                                      在光標(biāo)當(dāng)前所在字符位置的后面輸入文本數(shù)據(jù)。

    A                                     在光標(biāo)當(dāng)前所在行的行尾(也即最后一個(gè)字符位置)后面輸入文本數(shù)據(jù)。

    i                                       在光標(biāo)當(dāng)前所在字符位置的前面輸入文本數(shù)據(jù)。

    I                                      在光標(biāo)當(dāng)前所在行的行首(也即在第一個(gè)非空白的起始字符)前面輸入文本數(shù)據(jù)。

    o                                      在光標(biāo)當(dāng)前所在行下面的行首位置輸入文本數(shù)據(jù)。

    O                                     在光標(biāo)當(dāng)前所在行上面的行首位置輸入文本數(shù)據(jù)。

    4.     修改文本

    C                                     替換當(dāng)前文本行光標(biāo)所在字符位置之后的所有數(shù)據(jù),以Esc鍵結(jié)束。

    cw                                   替換光標(biāo)當(dāng)前所在字符位置及之后的整個(gè)字或部分字,以Esc鍵結(jié)束。

    [n]cc                                替換當(dāng)前行,或從當(dāng)前行開始的n行文本,以Esc鍵結(jié)束。

    [n]s                                  替換光標(biāo)當(dāng)前所在位置的單個(gè)字符,或從光標(biāo)當(dāng)前位置開始的n個(gè)字符,以Esc鍵結(jié)束。

    S                                     替換當(dāng)前行,以Esc鍵結(jié)束。

    r                                      替換光標(biāo)當(dāng)前所在位置的單個(gè)字符。

    r<Enter>                           斷行。也可使用“a”或“i”命令加Enter及Esc鍵實(shí)現(xiàn)。

    R                                     從光標(biāo)當(dāng)前所在的字符位置開始,替換隨后的所有字符,直至按下Esc鍵。

    xp                                    交換字符位置。交換光標(biāo)當(dāng)前所在位置開始字符位置。

    ~                                      轉(zhuǎn)換光標(biāo)當(dāng)前所在位置字符的大小寫。

    u                                      撤銷最近一次執(zhí)行的編輯命令,或依次撤銷先前執(zhí)行的編輯命令。

    :u                                     同上(ex編輯命令)。

    U                                     撤銷施與當(dāng)前文本行的編輯處理。

    5.     刪除文本

    [n]x                                 刪除光標(biāo)當(dāng)前所在位置的字符,或刪除從光標(biāo)當(dāng)前位置開始的n個(gè)字符。

    [n]X                                刪除光標(biāo)當(dāng)前所在位置的前一個(gè)字符,或刪除光標(biāo)當(dāng)前所在位置之前的n個(gè)字符。

    dw                                   刪除光標(biāo)當(dāng)前所在位置的一個(gè)整字或部分字符。如果光標(biāo)在字首,則刪除整字。如果光標(biāo)在字的中間任何位置,則刪除光標(biāo)位置及之后的字符。

    [n]dd                                刪除光標(biāo)當(dāng)前所在的文本行,或刪除從當(dāng)前行開始的n個(gè)文本行。

    D                                     刪除當(dāng)前文本行從光標(biāo)位置開始之后的所有字符。

    dG                                   刪除從當(dāng)前行開始直至文件最后一行的所有文本行。

    d[n]G                               刪除從文件的第n行開始直至當(dāng)前行的所有文本行。

    :line#1,line#2 d                  刪除從指定的行號(hào)line#1到line#2之間的所有文本行。

    6.     復(fù)制與移動(dòng)文本

    [n]yy                               復(fù)制光標(biāo)當(dāng)前所在的文本行,或從當(dāng)前行開始的n個(gè)文本行。

    [n]Y                                同上。

    p(小寫)                       把復(fù)制或刪除(“dd”命令)的文本行粘貼到光標(biāo)所在行的下面。

    P(大寫)                       把復(fù)制或刪除(“dd”命令)的文本行粘貼到光標(biāo)所在行的上面。

    :line#1,line#2 co line#3      把第line#1~line#2行復(fù)制到第line#3行之后。

    :line#1,line#2 m line#3       把第line#1~line#2行移至第line#3行之后。

    7.     設(shè)置行號(hào)顯示

    :set nu                              在編輯期間增加臨時(shí)行號(hào)。

    :set nonu                           撤銷行號(hào)顯示(默認(rèn)情況)。

    Ctrl+G                              顯示當(dāng)前文件的名字和當(dāng)前文本行的行號(hào)。

    8.     設(shè)置大小寫字母檢索準(zhǔn)則

    :set ic                                檢索字符串時(shí)忽略字母的大小寫。

    :set noic                            檢索字符串時(shí)嚴(yán)格區(qū)分字母的大小寫(默認(rèn)情況)。

    9.     定位文本行

    G                                     將光標(biāo)移至文件的組后一行。

    [n]G                                 將光標(biāo)移至文件的第n行。

    10. 檢索與替換

    :/string                              向前(文件結(jié)尾方向)檢索指定的字符串。

    :?string                             向后(文件開頭方向)檢索指定的字符串。

    n                                      將檢索方向找出下一個(gè)匹配的字符串。

    N                                     逆檢索方向找出前一個(gè)匹配的字符串。

    :[g]/search/s//replace/[g][c] 檢索并替換字符串。

    11. 清除屏幕

    Ctrl+L                              清除因其他進(jìn)程的輸出信息而干擾的編輯窗口。

    12. 合并文件與合并行

    :r filename                        在光標(biāo)所在行之后插入指定文件的內(nèi)容。

    : line#1 r filename              在第line#1行之后插入指定文件的內(nèi)容。

    J                                      把相鄰的兩個(gè)文本行個(gè)并為一行(把下一行合并到光標(biāo)當(dāng)前所在行的后面)。

    13. 保存編輯結(jié)果與退出vim編輯器

    :w                                    保存編輯處理后的結(jié)果(把內(nèi)存緩沖區(qū)中的數(shù)據(jù)寫到文件中)。

    :w!                                   強(qiáng)制保存編輯處理后的結(jié)果。

    :wq                                  保存編輯處理后的結(jié)果,然后退出vim編輯器。

    :wq!                                 強(qiáng)制保存編輯處理后的結(jié)果,然后退出vim編輯器。

    ZZ                                   保存編輯處理后的結(jié)果,然后退出vim編輯器。

    :q                                     在未做任何編輯處理時(shí),可以使用此命令退出vim編輯器。

    :q!                                    強(qiáng)制退出vim編輯器,放棄編輯處理后的結(jié)果。

    :w filename                       把編輯處理后的結(jié)果寫到指定的文件中保存。

    :w! filename                      把編輯處理后的結(jié)果強(qiáng)制寫到指定的文件中保存,即使文件已經(jīng)存在。

    :wq! filename                    把編輯處理后的結(jié)果強(qiáng)制寫到指定的文件中保存,即使文件已經(jīng)存在,然后退出vim編輯器。

    14. 其他

    ;f 或 Ctrl+G                     顯示文件的名字、編輯狀態(tài)、文件總的行數(shù)、光標(biāo)當(dāng)前所在行號(hào)和列號(hào),以及當(dāng)前行之前的行數(shù)占整個(gè)文件總行數(shù)的百分比。

    Ctrl+V                              輸入控制字符。

    posted @ 2012-09-04 17:07 brock 閱讀(323) | 評(píng)論 (0)編輯 收藏

    最近在使用Google的Gson包進(jìn)行Json和Java對(duì)象之間的轉(zhuǎn)化,對(duì)于包含泛型的類的序列化和反序列化Gson也提供了很好的支持,感覺有點(diǎn)意思,就花時(shí)間研究了一下。

    由于Java泛型的實(shí)現(xiàn)機(jī)制,使用了泛型的代碼在運(yùn)行期間相關(guān)的泛型參數(shù)的類型會(huì)被擦除,我們無法在運(yùn)行期間獲知泛型參數(shù)的具體類型(所有的泛型類型在運(yùn)行時(shí)都是Object類型)。

    但是有的時(shí)候,我們確實(shí)需要獲知泛型參數(shù)的類型,比如將使用了泛型的Java代碼序列化或者反序列化的時(shí)候,這個(gè)時(shí)候問題就變得比較棘手。

    1
    2
    3
    4
    5
    6
    7
    8
    class Foo<T> {
      T value;
    }
    Gson gson = new Gson();
    Foo<Bar> foo = new Foo<Bar>();
    gson.toJson(foo); // May not serialize foo.value correctly
     
    gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

     

    對(duì)于上面的類Foo<T>,由于在運(yùn)行期間無法得知T的具體類型,對(duì)這個(gè)類的對(duì)象進(jìn)行序列化和反序列化都不能正常進(jìn)行。Gson通過借助TypeToken類來解決這個(gè)問題。

    1
    2
    3
    4
    5
    6
    7
    8
    TestGeneric<String> t = new TestGeneric<String>();
      t.setValue("Alo");
      Type type = new TypeToken<TestGeneric<String>>(){}.getType();
       
      String gStr = GsonUtils.gson.toJson(t,type);
      System.out.println(gStr);
      TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type);
      System.out.println(t1.getValue());

     

    TypeToken的使用非常簡(jiǎn)單,如上面的代碼,只要將需要獲取類型的泛型類作為TypeToken的泛型參數(shù)構(gòu)造一個(gè)匿名的子類,就可以通過getType()方法獲取到我們使用的泛型類的泛型參數(shù)類型。

    下面來簡(jiǎn)單分析一下原理。

    要獲取泛型參數(shù)的類型,一般的做法是在使用了泛型的類的構(gòu)造函數(shù)中顯示地傳入泛型類的Class類型作為這個(gè)泛型類的私有屬性,它保存了泛型類的類型信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Foo<T>{
      
     public Class<T> kind;
      
     public Foo(Class<T> clazz){
      this.kind = clazz;
     }
      
     public T[] getInstance(){
      return (T[])Array.newInstance(kind, 5);
     }
      
     public static void main(String[] args){
      Foo<String> foo = new Foo(String.class);
      String[] strArray = foo.getInstance();
     }
     
    }

     

    這種方法雖然能解決問題,但是每次都要傳入一個(gè)Class類參數(shù),顯得比較麻煩。Gson庫(kù)里面對(duì)于這個(gè)問題采用了了另一種解決辦法。

    同樣是為了獲取Class的類型,可以通過另一種方式實(shí)現(xiàn):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public abstract class Foo<T>{
      
     Class<T> type;
      
     public Foo(){
      this.type = (Class<T>) getClass();
     }
     
            public static void main(String[] args) {
       
      Foo<String> foo = new Foo<String>(){};
      Class mySuperClass = foo.getClass();
     
     }
      
    }

     

    聲明一個(gè)抽象的父類Foo,匿名子類將泛型類作為Foo的泛型參數(shù)傳入構(gòu)造一個(gè)實(shí)例,再調(diào)用getClass方法獲得這個(gè)子類的Class類型。

    這里雖然通過另一種方式獲得了匿名子類的Class類型,但是并沒有直接將泛型參數(shù)T的Class類型傳進(jìn)來,那又是如何獲得泛型參數(shù)的類型的呢, 這要依賴Java的Class字節(jié)碼中存儲(chǔ)的泛型參數(shù)信息。Java的泛型機(jī)制雖然在運(yùn)行期間泛型類和非泛型類都相同,但是在編譯java源代碼成 class文件中還是保存了泛型相關(guān)的信息,這些信息被保存在class字節(jié)碼常量池中,使用了泛型的代碼處會(huì)生成一個(gè)signature簽名字段,通過 簽名signature字段指明這個(gè)常量池的地址。

    關(guān)于class文件中存儲(chǔ)泛型參數(shù)類型的具體的詳細(xì)的知識(shí)可以參考這里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

    JDK里面提供了方法去讀取這些泛型信息的方法,再借助反射,就可以獲得泛型參數(shù)的具體類型。同樣是對(duì)于第一段代碼中的foo對(duì)象,通過下面的代碼可以得到foo<T>中的T的類型:

    1
    2
    3
    Type mySuperClass = foo.getClass().getGenericSuperclass();
      Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
    System.out.println(type);

     

    運(yùn)行結(jié)果是class java.lang.String。

    分析一下這段代碼,Class類的getGenericSuperClass()方法的注釋是:

    Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass.

    If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned

    概括來說就是對(duì)于帶有泛型的class,返回一個(gè)ParameterizedType對(duì)象,對(duì)于Object、接口和原始類型返回null,對(duì)于數(shù) 組class則是返回Object.class。ParameterizedType是表示帶有泛型參數(shù)的類型的Java類型,JDK1.5引入了泛型之 后,Java中所有的Class都實(shí)現(xiàn)了Type接口,ParameterizedType則是繼承了Type接口,所有包含泛型的Class類都會(huì)實(shí)現(xiàn) 這個(gè)接口。

    實(shí)際運(yùn)用中還要考慮比較多的情況,比如獲得泛型參數(shù)的個(gè)數(shù)避免數(shù)組越界等,具體可以參看Gson中的TypeToken類及ParameterizedTypeImpl類的代碼。

    posted @ 2012-08-01 16:26 brock 閱讀(42680) | 評(píng)論 (6)編輯 收藏

    僅列出標(biāo)題
    共15頁(yè): 上一頁(yè) 1 2 3 4 5 6 7 8 9 下一頁(yè) Last 
    主站蜘蛛池模板: 午夜精品在线免费观看| 国产精品jizz在线观看免费| 午夜视频免费观看| 久久精品国产亚洲Aⅴ蜜臀色欲| 久久久久亚洲AV无码专区首| 亚洲午夜福利在线视频| 免费无码又爽又刺激网站直播| 成人A级毛片免费观看AV网站| 亚洲天堂在线视频| 亚洲AV无码一区二区三区人| 国产大片免费天天看| 色se01短视频永久免费| 中文字幕亚洲不卡在线亚瑟| 精品亚洲成在人线AV无码| 精品久久久久久国产免费了 | 亚洲人成人网站色www| 亚洲熟妇AV一区二区三区浪潮 | 99视频免费播放| 免费a级毛片无码a∨性按摩| 亚洲自偷精品视频自拍| 一个人免费观看视频在线中文| 成年女人18级毛片毛片免费观看| 日韩亚洲一区二区三区| 免费看黄网站在线看| 福利免费观看午夜体检区| 久久亚洲高清观看| 国产亚洲Av综合人人澡精品| 国产成人精品免费视| 亚洲精品无码永久在线观看你懂的| 亚洲精品人成网线在线播放va| 91av免费观看| 亚洲日韩精品射精日| 美女被吸屁股免费网站| 青青草免费在线视频| 亚洲精品mv在线观看| 免费无码又爽又刺激高潮软件| 免费人成在线观看视频播放| 亚洲人成人网毛片在线播放| 91精品手机国产免费| 亚洲狠狠婷婷综合久久久久| 女人裸身j部免费视频无遮挡|