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

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

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

    super

    2010年6月30日 #

    使用 apache common dbcp +common pool+mysql連接無效的問題




    Throwable occurred: org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 50,123,505 milliseconds ago.  The last packet sent successfully to the server was 50,123,505 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.


    這主要是由兩個原因引起來的:
    1.mysql 會自動關閉長時間不用的connection,一個連接如果處于sleep狀態達到mysql的參數wait_timeout指定的時間(默認為8小時),就是自動關閉這個連接
    2.common pool中沒有指定相應的連接檢查參數


    解決辦法:從common pool的配置參數來解決:

     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
      <property name="driverClassName">
       <value>${db.driver}</value>
      </property>
      <property name="url">
       <value>${db.url}</value>
      </property>
      <property name="username">
       <value>${db.user}</value>
      </property>
      <property name="password">
       <value>${db.password}</value>
      </property>
      <property name="maxActive">
       <value>100</value>
      </property>
      <property name="maxIdle">
       <value>50</value>
      </property>
      <property name="maxWait">
       <value>10000</value>
      </property>


      <property name="timeBetweenEvictionRunsMillis">
       <value>3600000</value><!--1 hours-->
      </property>

    <!--
      <property name="minEvictableIdleTimeMillis">
       <value>20000</value>
      </property>
    -->
      
      <property name="testWhileIdle">
       <value>true</value>
      </property>
      <property name="validationQuery">
       <value>select 1 from dual</value>
      </property>

     </bean>

    使用上述的三個紅色的參數,就可以避免這個問題.這三個參數的意義:

    timeBetweenEvictionRunsMillis:啟動connection校驗定時器,定時器運行時間間隔就是timeBetweenEvictionRunsMillis的值.默認為-1,表示不啟動定時器,這里設定為1小時,只要小于mysql的wait_timeout就可以了

    testWhileIdle: true,表示檢查idle的connection,false為不檢查

    validationQuery:用于檢查connection的sql語句.


    這只是一種方法,另外的幾種方法:

    timeBetweenEvictionRunsMillis+minEvictableIdleTimeMillis:這種方式不檢查Connection的有效性,而是檢查連接的空閑時間,大于minEvictableIdleTimeMillis就清除.

      <property name="timeBetweenEvictionRunsMillis">
       <value>3600000</value><!--1 hours-->
      </property>

      <property name="minEvictableIdleTimeMillis">
       <value>120000</value><!--connection的空閑時間大于這個值,就直接被關閉,并從連接池中刪除-->
      </property>


    如果不喜歡用定時器,也可以配置testOnBorrow+validationQuery參數:每次從連接池取參數都會校驗連接的有效性.實際上這種方式性能會比定時器差些.
      <property name="testOnBorrow">
       <value>true</value>
      </property>
      <property name="validationQuery">
       <value>select 1 from dual</value>
      </property>


    另外,也可以用testOnReturn+validationQuery,不過未必會解決問題:這表示每次使用完連接,歸還連接池的時候檢查連接的有效性,這有可能導致使用一次無效的連接,最好不要用.


    上面的幾種方法可以合并使用,只是檢查的點多了,未必是好事


    另外,也可以使用Abandoned的那幾個參數,來刪除連接池中的連接.也能達到效果.我沒測試.











    posted @ 2010-09-15 17:57 王衛華 閱讀(2439) | 評論 (0)編輯 收藏

    android中點中overlay彈出帶尾巴的氣泡的實現




    就是上面的樣子

    做這個過程中我碰到兩個問題:
    1:如何做帶尾巴的氣泡View
    2:如何把這個View添加到MapView中.


    1:如何做帶尾巴的氣泡View
    我是采用背景圖的方式來實現的.當然,普通的PNG在View 縮放的時候會失真,尤其是那個尖尖的尾巴.
    后來采用9.png的格式,才完成了不變形的效果.9.png格式的Png可以用SDK\Tools\draw9patch.bat來處理,只要把普通的png的邊上標志一下就可以了,具體draw9patch.bat如何使用這里就不說了,網上有很多文檔,自己查查就知道了.
    我生成的9.png就是下面這個樣子,注意四周的黑線.就是9png拉伸時的標識


    有了這個png,直接放到你的工程下的res/drawable目錄就可以了,
    然后在res/layout目錄下建立你的view的xml文件,比如叫overlay_pop.xml,我的是這樣的:

    <?xml version="1.0" encoding="UTF-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:background="@drawable/bubble_background" <!--這就是那個9.png-->
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:paddingLeft="5px"
     android:paddingTop="5px"
     android:paddingRight="5px"
     android:paddingBottom="20px"    <!--注意加上padding,否則view里面的東西就畫到邊框上了-->
       >
        <TextView android:id="@+id/map_bubbleTitle"
           android:ellipsize="marquee"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:gravity="center_horizontal"
           android:singleLine="true"
           style="@style/map_BubblePrimary" /> <!--style可以沒有,我這里第一個TextView表示標題,用的是大字體-->
        <TextView  android:id="@+id/map_bubbleText"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:singleLine="false"
           style="@style/map_BubbleSecondary" /><!--style可以沒有,我這里第二個TextView表示描述信息,用的是大字體-->
    </LinearLayout>


    這樣popView就建立好了


    2:如何把這個View添加到MapView中.
    通常是在mapView中點擊某個位置,彈出popView
    或者點擊某個Overlay彈出popView,這里用點擊Overlay來說明,

    overlay有onTap()方法,你可以實現自己的overlay,overideonTap()方法,彈出popView,
    也可以使用setOnFocusChangeListener(),在listener中實現彈出popView,.
    我是用的listener,因為setOnFocusChangeListener在失去焦點也會觸發,我可以再失去焦點的時候隱藏popView.

    MapView是繼承自ViewGroup的,因此,MapView有addView()方法,同時還有MapView.LayoutParams
    MapView.LayoutParams 可以根據GeoPoint來定位,我就是利用這個特性來定位彈出的popView的.

    PointItemizedOverlay overlay = new PointItemizedOverlay(drawable); <!--這是我繼承自ItemizedOverlay的overlay,主要就是畫一個圖片,寫一個名稱,很簡單,這里不貼具體代碼了-->

    public class BaseMapActivity extends MapActivity {

     /**
      * 地圖View
      */
     protected MapView mapView;

     /**
      * 彈出的氣泡View
      */
     private View popView;
    /**
        監聽器
    */
     private final ItemizedOverlay.OnFocusChangeListener onFocusChangeListener = new ItemizedOverlay.OnFocusChangeListener() {

      @Override
      public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus) {
          //創建氣泡窗口
     

       if (popView != null) {
          popView.setVisibility(View.GONE);
       }

       if (newFocus != null) {

        MapView.LayoutParams geoLP = (MapView.LayoutParams) popView.getLayoutParams();
        geoLP.point = newFocus.getPoint();//這行用于popView的定位
        TextView title = (TextView) popView.findViewById(R.id.map_bubbleTitle);
        title.setText(newFocus.getTitle());

        TextView desc = (TextView) popView.findViewById(R.id.map_bubbleText);
        if (newFocus.getSnippet() == null || newFocus.getSnippet().length() == 0) {
         desc.setVisibility(View.GONE);
        } else {
         desc.setVisibility(View.VISIBLE);
         desc.setText(newFocus.getSnippet());
        }
        mapView.updateViewLayout(popView, geoLP);
        popView.setVisibility(View.VISIBLE);
       }
      }
     };




         public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
                /**
                省略其他代碼
               **/

              //初始化氣泡,并設置為不可見

           popView = inflater.inflate(R.layout.overlay_popup, null);
           mapView.addView( popView,
                 new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT,
               null, MapView.LayoutParams.BOTTOM_CENTER));
              //由于我的氣泡的尾巴是在下邊居中的,因此要設置成MapView.LayoutParams.BOTTOM_CENTER.
              //這里沒有給GeoPoint,在onFocusChangeListener中設置
           views.add(popView);
          popView.setVisibility(View.GONE);

        添加overlay
        PointItemizedOverlay overlay = new PointItemizedOverlay(drawable);
        //設置顯示/隱藏泡泡的監聽器
        overlay.setOnFocusChangeListener(onFocusChangeListener);
        overlay.addOverlay(/*你自己的overlayItem*/);
        overlay.addOverlay(/*你自己的overlayItem*/);
        overlay.addOverlay(/*你自己的overlayItem*/);

        }
    }

    這樣就基本完工了.




    posted @ 2010-08-12 15:03 王衛華 閱讀(5698) | 評論 (7)編輯 收藏

    android mapView中畫軌跡的overlay


    使用方法:
    LineItemizedOverlay overlay = new LineItemizedOverlay();

    overlay.addOverlay(/*起點的OverlayItem*/);
    overlay.addOverlay(/*終點的OverlayItem*/);
    overlay.addLinePoint(/*要畫的軌跡的GeoPoint的List*/);

    mapView.getOverlays().add(overlay);

    /**
     *
     */
    package com.xtyon.tuola.truck.map;

    import java.util.ArrayList;

    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.graphics.drawable.Drawable;

    import com.google.android.maps.GeoPoint;
    import com.google.android.maps.ItemizedOverlay;
    import com.google.android.maps.MapView;
    import com.google.android.maps.OverlayItem;
    import com.google.android.maps.Projection;

    /**
     * 地圖上的線型圖層:包括一個起點,一個終點,以及之間的曲線
     * @author superwang
     */
    public class LineItemizedOverlay extends ItemizedOverlay<OverlayItem> {
     private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
       | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
     /**
      * 用于保存起點/終點數據
      */
     private final ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();

     /**
      * 用于保存構成曲線的點的數據
      */
     private final ArrayList<GeoPoint> linePoints = new ArrayList<GeoPoint>();

     /**
      * @param defaultMarker
      */
     public LineItemizedOverlay() {
      super(null);

      // TODO Auto-generated constructor stub
     }

     /* (non-Javadoc)
      * @see com.google.android.maps.ItemizedOverlay#createItem(int)
      */
     @Override
     protected OverlayItem createItem(int i) {
      return mOverlays.get(i);

     }

     /* (non-Javadoc)
      * @see com.google.android.maps.ItemizedOverlay#size()
      */
     @Override
     public int size() {
      // TODO Auto-generated method stub
      return mOverlays.size();
     }

     /**
      * 調價起點/終點
      * description:
      * @param overlay
      */
     public void addOverlay(OverlayItem overlay) {
      mOverlays.add(overlay);
      populate();
     }

     /**
      * 添加曲線中的點
      * description:
      * @param point
      */
     public void addLinePoint(GeoPoint point) {
      linePoints.add(point);
     }

     public ArrayList<GeoPoint> getLinePoints() {
      return linePoints;
     }

     /**
      * 畫起點/終點/軌跡
      */
     @Override
     public void draw(Canvas canvas, MapView mapView, boolean shadow) {
      if (!shadow) {
       //System.out.println("!!!!!!!!!!!!!!");

       canvas.save(LAYER_FLAGS);
       //canvas.save();

       Projection projection = mapView.getProjection();
       int size = mOverlays.size();
       Point point = new Point();
       Paint paint = new Paint();
       paint.setAntiAlias(true);
       OverlayItem overLayItem;

       //畫起點/終點
       for (int i = 0; i < size; i++) {

        overLayItem = mOverlays.get(i);

        Drawable marker = overLayItem.getMarker(0);
        //marker.getBounds()
        /* 象素點取得轉換 */
        projection.toPixels(overLayItem.getPoint(), point);

        if (marker != null) {
         boundCenterBottom(marker);
        }

        /* 圓圈 */
        //Paint paintCircle = new Paint();
        //paintCircle.setColor(Color.RED);
        paint.setColor(Color.RED);
        canvas.drawCircle(point.x, point.y, 5, paint);

        /* 文字設置 */
        /* 標題 */
        String title = overLayItem.getTitle();
        /* 簡介 */
        //    String snippet = overLayItem.getSnippet();
        //
        //    StringBuffer txt = new StringBuffer();
        //    if (title != null && !"".equals(title))
        //     txt.append(title);
        //
        //    if (snippet != null && !"".equals(snippet)) {
        //     if (txt.length() > 0) {
        //      txt.append(":");
        //     }
        //     txt.append(snippet);
        //    }    
        //Paint paintText = new Paint();

        if (title != null && title.length() > 0) {
         paint.setColor(Color.BLACK);
         paint.setTextSize(15);
         canvas.drawText(title, point.x, point.y, paint);
        }

       }

       //畫線

       boolean prevInBound = false;//前一個點是否在可視區域
       Point prev = null;
       int mapWidth = mapView.getWidth();
       int mapHeight = mapView.getHeight();
       //Paint paintLine = new Paint();
       paint.setColor(Color.RED);
       //paint.setPathEffect(new CornerPathEffect(10));
       paint.setStrokeWidth(2);
       int count = linePoints.size();

       //Path path = new Path();
       //path.setFillType(Path.FillType.INVERSE_WINDING);
       for (int i = 0; i < count; i++) {
        GeoPoint geoPoint = linePoints.get(i);
        //projection.toPixels(geoPoint, point); //這一行似乎有問題
        point = projection.toPixels(geoPoint, null);
        if (prev != null) {
         if (point.x >= 0 && point.x <= mapWidth && point.y >= 0 && point.y <= mapHeight) {
          if ((Math.abs(prev.x - point.x) > 2 || Math.abs(prev.y - point.y) > 2)) {
           //這里判斷點是否重合,重合的不畫線,可能會導致畫線不在路上
           canvas.drawLine(prev.x, prev.y, point.x, point.y, paint);
           //path.lineTo(point.x, point.y);

           prev = point;
           prevInBound = true;

          }
         } else {
          //在可視區與之外
          if (prevInBound) {//前一個點在可視區域內,也需要劃線
           //path.lineTo(point.x, point.y);
           canvas.drawLine(prev.x, prev.y, point.x, point.y, paint);
          }
          prev = point;
          prevInBound = false;
         }
        } else {
         //path.moveTo(point.x, point.y);
         prev = point;

        }
       }
       //canvas.drawPath(path, paint);
       canvas.restore();
       //DebugUtils.showMemory();
      }
      super.draw(canvas, mapView, shadow);
     }

    }

    posted @ 2010-08-12 14:21 王衛華 閱讀(1682) | 評論 (0)編輯 收藏

    tomcat reload時內存泄漏的處理

    我做的應用是以Spring為系統的基礎框架,mysql為后臺數據庫.在tomcat上發布后,總是不能進行熱部署(reload),多次reload后,就會出OutOfMemory PermGen,

    為此煩惱了很久,總于下定決心找找根源.
    經過3天的不懈努力,小有成果,記錄下來

    實際上下面的分析都已經沒什么用了,如果你使用tomcat6.0.26及以后的版本,我所說的這些情況都已經被處理了,并且比我處理的還要多很多.可以下載tomcat6.0.26的源代碼
    看看WebappClassLoader類的處理就成了.

     

    通過分析工具的分析(用了YourKit,以及JDK1.6/bin下的jps/jmap/jhat),發現有下面幾個方面會造成memory leak.

    1.SystemClassLoader與WebappClassLoader加載的類相互引用,tomcat reload只是卸載WebappClassloader中的class,SystemClassLoader是不會卸載的(否則其他應用也停止了).但是WebappClassloader加載的類被SystemClassLoader引用的化,WebappClassloader中的相關類就不會被JVM進行垃圾收集

    目前發現2種容易產生這種leak的現象.
    a.在使用java.lang.ThreadLocal的時候很容易產生這種情況
    b.使用jdbc驅動,而且不是在tomcat中配置的公共連接池.則java.sql.DriverManager一定會產生這種現象


    ThreadLocal.set(Object),如果這個Object是WebappsClassLoader加載的,使用之后沒有做ThreadLocal.set(null)或者ThreadLocal.remove(),就會產生memory leak.
    由于ThreadLocal實際上操作的是java.lang.Thread類中的ThreadLocalMap,Thread類是由SystemClassLoder加載的.而這個線程實例(main thread)在tomcat reload的時候不會銷毀重建,必然就產生了SystemClassLoder中的類引用WebappsClassLoader的類.

    DriverManager也是由SystemClassLoder載入的,當初始化某個JDBC驅動的時候,會向DriverManager中注冊該驅動,通常是***.driver,例如com.mysql.jdbc.Driver
    這個Driver是通過class.forName()加載的,通常也是加載到WebappClassLoader.這就出現了兩個classLoader中的類的交叉引用.導致memory leak.

     

    解決辦法:
    寫一個ServletContextListener,在contextDestroyed方法中統一刪除當前Thread的ThreadLocalMap中的內容.
    public class ApplicationCleanListener implements ServletContextListener {

     public void contextInitialized(ServletContextEvent event) {
     }

     public void contextDestroyed(ServletContextEvent event) {
             //處理ThreadLocal
      ThreadLocalCleanUtil.clearThreadLocals();

      /*
       * 如果數據故驅動是通過應用服務器(tomcat etc...)中配置的<公用>連接池,這里不需要 否則必須卸載Driver
       *
       * 原因: DriverManager是System classloader加載的, Driver是webappclassloader加載的,
       * driver保存在DriverManager中,在reload過程中,由于system
       * classloader不會銷毀,driverManager就一直保持著對driver的引用,
       * driver無法卸載,與driver關聯的其他類
       * ,例如DataSource,jdbcTemplate,dao,service....都無法卸載
       */
      try {
       System.out.println("clean jdbc Driver......");
       for (Enumeration e = DriverManager.getDrivers(); e
         .hasMoreElements();) {
        Driver driver = (Driver) e.nextElement();
        if (driver.getClass().getClassLoader() == getClass()
          .getClassLoader()) {
         DriverManager.deregisterDriver(driver);
        }
       }

      } catch (Exception e) {
       System.out
         .println("Exception cleaning up java.sql.DriverManager's driver: "
           + e.getMessage());
      }


     }

    }


    /**
     * 這個類根據
    */
    public class ThreadLocalCleanUtil {

     /**
      * 得到當前線程組中的所有線程 description:
      *
      * @return
      */
     private static Thread[] getThreads() {
      ThreadGroup tg = Thread.currentThread().getThreadGroup();

      while (tg.getParent() != null) {
       tg = tg.getParent();
      }

      int threadCountGuess = tg.activeCount() + 50;
      Thread[] threads = new Thread[threadCountGuess];
      int threadCountActual = tg.enumerate(threads);

      while (threadCountActual == threadCountGuess) {
       threadCountGuess *= 2;
       threads = new Thread[threadCountGuess];

       threadCountActual = tg.enumerate(threads);
      }

      return threads;
     }

     public static void clearThreadLocals() {
      ClassLoader classloader = Thread
        .currentThread()
        .getContextClassLoader();

      Thread[] threads = getThreads();
      try {
       Field threadLocalsField = Thread.class
         .getDeclaredField("threadLocals");

       threadLocalsField.setAccessible(true);
       Field inheritableThreadLocalsField = Thread.class
         .getDeclaredField("inheritableThreadLocals");

       inheritableThreadLocalsField.setAccessible(true);

       Class tlmClass = Class
         .forName("java.lang.ThreadLocal$ThreadLocalMap");

       Field tableField = tlmClass.getDeclaredField("table");
       tableField.setAccessible(true);

       for (int i = 0; i < threads.length; ++i) {
        if (threads[i] == null)
         continue;
        Object threadLocalMap = threadLocalsField.get(threads[i]);
        clearThreadLocalMap(threadLocalMap, tableField, classloader);

        threadLocalMap = inheritableThreadLocalsField.get(threads[i]);

        clearThreadLocalMap(threadLocalMap, tableField, classloader);
       }
      } catch (Exception e) {

       e.printStackTrace();
      }
     }

     private static void clearThreadLocalMap(Object map,
       Field internalTableField, ClassLoader classloader)
       throws NoSuchMethodException, IllegalAccessException,
       NoSuchFieldException, InvocationTargetException {
      if (map != null) {
       Method mapRemove = map.getClass().getDeclaredMethod("remove",
         new Class[] { ThreadLocal.class });

       mapRemove.setAccessible(true);
       Object[] table = (Object[]) internalTableField.get(map);
       int staleEntriesCount = 0;
       if (table != null) {
        for (int j = 0; j < table.length; ++j) {
         if (table[j] != null) {
          boolean remove = false;

          Object key = ((Reference) table[j]).get();
          if ((key != null)
            && (key.getClass().getClassLoader() == classloader)) {
           remove = true;

           System.out.println("clean threadLocal key,class="
             + key.getClass().getCanonicalName()
             + ",value=" + key.toString());
          }

          Field valueField = table[j]
            .getClass()
            .getDeclaredField("value");

          valueField.setAccessible(true);
          Object value = valueField.get(table[j]);

          if ((value != null)
            && (value.getClass().getClassLoader() == classloader)) {
           remove = true;
           System.out.println("clean threadLocal value,class="
             + value.getClass().getCanonicalName()
             + ",value=" + value.toString());

          }

          if (remove) {

           if (key == null)
            ++staleEntriesCount;
           else {
            mapRemove.invoke(map, new Object[] { key });
           }
          }
         }
        }
       }
       if (staleEntriesCount > 0) {
        Method mapRemoveStale = map
          .getClass()
          .getDeclaredMethod("expungeStaleEntries", new Class[0]);

        mapRemoveStale.setAccessible(true);
        mapRemoveStale.invoke(map, new Object[0]);
       }
      }
     }
    }

     

    2.對于使用mysql JDBC驅動的:mysql JDBC驅動會啟動一個Timer Thread,這個線程在reload的時候也是無法自動銷毀.
      因此,需要強制結束這個timer
     
      可以在 上面的ApplicationCleanListener中加入如下代碼:

        try {
       Class ConnectionImplClass = Thread
         .currentThread()
         .getContextClassLoader()
         .loadClass("com.mysql.jdbc.ConnectionImpl");
       if (ConnectionImplClass != null
         && ConnectionImplClass.getClassLoader() == getClass()
           .getClassLoader()) {
        System.out.println("clean mysql timer......");
        Field f = ConnectionImplClass.getDeclaredField("cancelTimer");
        f.setAccessible(true);
        Timer timer = (Timer) f.get(null);
        timer.cancel();
       }
      } catch (java.lang.ClassNotFoundException e1) {
       // do nothing
      } catch (Exception e) {
       System.out
         .println("Exception cleaning up MySQL cancellation timer: "
           + e.getMessage());
      }

     


    3.common-logging+log4j似乎也會導致leak,看網上有人說在ApplicationCleanListene6中加入這行代碼就可以:
     LogFactory.release(Thread.currentThread().getContextClassLoader());

      我沒試成功,懶得再找原因,直接換成了slf4j+logback,沒有問題.據說slf4j+logback的性能還要更好.

     

     
    后記:
     tomcat-6.0.26之前的版本(我用的是tomcat-6.0.18),加入上述ApplicationCleanListener后,多次reload,不會出現outOfMemory.
     但要注意,第一次啟動后,reload一次,內存會增加,也就是看著還是由memory Leak,但是重復reload,內存始終保持在第一次reload的大小.似乎tomcat始終保留了雙WebappClassLoader.因此,配置內存要小心些,至少要保證能夠load兩倍的你的所有jar包的大小(當然,是指Perm的內存大小).
     
     測試過程中最好加上 JVM參數 -verbosegc,這樣,在做GC的時候可以直觀的看到class被卸載.

     

     

     

     

    posted @ 2010-06-30 18:10 王衛華 閱讀(3920) | 評論 (1)編輯 收藏

    主站蜘蛛池模板: 亚洲夜夜欢A∨一区二区三区| 国产精品视频免费一区二区三区| 国产精品亚洲片在线观看不卡| 免费在线观看一区| 亚洲精品国产高清嫩草影院| 国产精品亚洲一区二区无码 | 久久精品亚洲综合专区| 99免费在线观看视频| 亚洲精品亚洲人成在线观看麻豆 | 精品亚洲一区二区| 老司机69精品成免费视频| 亚洲日韩图片专区第1页| 99re6在线精品视频免费播放 | 亚洲精品免费在线| 成年女人18级毛片毛片免费| 激情无码亚洲一区二区三区| 亚洲国产精品毛片av不卡在线 | 久久久久免费精品国产小说| 久久精品国产亚洲AV电影| 国产精品成人免费一区二区 | 久久精品无码一区二区三区免费| 亚洲暴爽av人人爽日日碰| 亚洲男人的天堂在线va拉文| 久久精品免费电影| 国产亚洲精品bv在线观看| 无码专区—VA亚洲V天堂| 国产真人无码作爱视频免费| 久久久无码精品亚洲日韩按摩| 猫咪社区免费资源在线观看| 一级毛片在线免费视频| 亚洲国产综合专区在线电影| 啦啦啦手机完整免费高清观看 | 亚洲伊人久久大香线蕉啊| 日韩免费视频在线观看| 精品国产麻豆免费人成网站| 午夜在线a亚洲v天堂网2019| 区久久AAA片69亚洲| 久草视频免费在线| 美女无遮挡拍拍拍免费视频| 亚洲AV无码一区二区三区人| 伊人亚洲综合青草青草久热|