2016-07-27 46 views
0

Ivam面臨這個內存問題,它讓我瘋狂。 我的應用程序正在接收來自樹莓的二進制數據。有了這個數據我創建一個int數組,而不是使用它來創建我的位圖和顯示圖像的顏色。傳輸協議是UDP。 當我收到一張圖像時沒有問題,但是當我要求我的樹莓發送10張圖像時,此消息出現GC_FOR_ALLOC,有時傳送停止而沒有發送所有圖像。 我googled這個問題,我添加了Runtime.getRuntime()。gc();的System.gc();我的代碼和同樣的問題。 我將所有對象都聲明爲循環外,以避免每次創建新變量,使用createBitmap(int []顏色,int寬度,int高度,Bitmap.Config配置)創建我的位圖Im時,我在互聯網上閱讀執行此方法並不好,而使用createScaledBitmap(位圖src,int dstWidth,int dstHeight,布爾過濾器)。 問題我不知道如何使用我的數組顏色與createScaledBitmap方法。 另外,我在我的循環結束時嘗試了bitmap.recycle,它發送第一個圖像,然後我有一個錯誤,「試圖使用回收」。 請有人可以幫助我。 我可以添加我的代碼,如果你想。 謝謝 這是代碼:很多GC_FOR_ALLOC,有時當這個警告是無限的時候停止傳輸

class UDPServer { 
     MainActivity act; 

     final String capitalizedSentence = "well received!"; 
     final byte[] sendData = capitalizedSentence.getBytes(); 

     public UDPServer(MainActivity act) { 
      this.act=act; 
     } 


     public void connect() throws Exception { 
      final ImageView image = (ImageView) act.findViewById(R.id.imageDisplay); 
      final byte[] receiveData1=new byte[40960], receiveData2=new byte[40960], receiveData3=new byte[40960], receiveData4=new byte[40960]; 
      final DatagramSocket serverSocket=new DatagramSocket(8080); 
      final DatagramPacket receivePacket1 = new DatagramPacket(receiveData1, receiveData1.length); 
      final DatagramPacket receivePacket2 = new DatagramPacket(receiveData2, receiveData2.length); 
      final DatagramPacket receivePacket3 = new DatagramPacket(receiveData3, receiveData3.length); 
      final DatagramPacket receivePacket4 = new DatagramPacket(receiveData4, receiveData4.length); 

      final Thread udpserver = new Thread() 
      { 
        public void run() { 



         try { 
          while (!isInterrupted()) { 


           System.out.println("waiting for the conx"); 


           serverSocket.receive(receivePacket1); 
           serverSocket.receive(receivePacket2); 
           serverSocket.receive(receivePacket3); 
           serverSocket.receive(receivePacket4); 

           System.out.println("thank you sir"); 



           final Bitmap bitmap=Bitmap.createBitmap(act.afficheImage(
             receivePacket1.getData(), 
             receivePacket2.getData(), 
             receivePacket3.getData(), 
             receivePacket4.getData()), 
             320, 256, Bitmap.Config.ARGB_8888); 


           act.runOnUiThread(new Runnable() { 
            @Override 
            public void run() { 
             // TODO Auto-generated method stub 

             image.setImageBitmap(bitmap); 
            } 
           }); 
           InetAddress IPAddress = receivePacket1.getAddress(); 
           int port = receivePacket1.getPort(); 
           System.out.println("From: " + IPAddress + ":" + port); 
           DatagramPacket sendPacket1 = new DatagramPacket(sendData, sendData.length, IPAddress, port); 
           serverSocket.send(sendPacket1); 

           Runtime.getRuntime().gc(); 
           System.gc(); 
          } 
          serverSocket.close(); 
         } catch (SocketException ex) { 
          System.out.println("UDP Port 8080 is occupied."); 
         } catch (IOException ex1) { 
          System.out.println("Error: " + ex1.getMessage()); 
          ex1.printStackTrace(); 
         } 
        } 
      }; 
     udpserver.start(); 
     } 
    } 

這是方法afficheImage:

private static final int WIDTH = 320; 
    private static final int HEIGHT = 256; 
    public static int a=255<<24; 
    public static ByteBuffer buffer1; 
    public static short[] array=new short[WIDTH * HEIGHT]; 
    public static byte[] si=new byte[2]; 
    public static int[] colors = new int[WIDTH * HEIGHT]; 
    public static int[] afficheImage(byte[] s1, byte[] s2, byte[] s3, byte[] s4){ 
     try{ 
      for (int i=0;i<HEIGHT*WIDTH/4;i++){ 
       si[0] = s1[2*i]; 
       si[1] = s1[2*i+1]; 
       buffer1 = ByteBuffer.wrap(si); 
       buffer1.order(ByteOrder.LITTLE_ENDIAN); 
       array[i]=buffer1.getShort(); 
      } 

      for (int i=0;i<HEIGHT*WIDTH/4;i++){ 
       si[0] = s2[2*i]; 
       si[1] = s2[2*i+1]; 
       buffer1 = ByteBuffer.wrap(si); 
       buffer1.order(ByteOrder.LITTLE_ENDIAN); 
       array[i+s1.length/2]=buffer1.getShort(); 
      } 

      for (int i=0;i<HEIGHT*WIDTH/4;i++){ 
       si[0] = s3[2*i]; 
       si[1] = s3[2*i+1]; 
       buffer1 = ByteBuffer.wrap(si); 
       buffer1.order(ByteOrder.LITTLE_ENDIAN); 
       array[i+s1.length]=buffer1.getShort(); 
      } 

      for (int i=0;i<HEIGHT*WIDTH/4;i++){ 
       si[0] = s4[2*i]; 
       si[1] = s4[2*i+1]; 
       buffer1 = ByteBuffer.wrap(si); 
       buffer1.order(ByteOrder.LITTLE_ENDIAN); 
       array[i+3*s1.length/2]=buffer1.getShort(); 
      } 


      int delta=foundMax(array)-foundMin(array); 
      int min=foundMin(array); 

      int r; 

      for (int i=0;i<HEIGHT*WIDTH;i++) { 
       r = (array[i] - min) * 255/delta; 
       colors[i] = a | (r << 16) | (r << 8) | r; 
      } 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 

     return colors; 
    } 
+0

Raspberry發送的圖像的尺寸是多少?另外,你是否知道像素配置,例如ARGB_8888? –

+0

我早些時候回答了關於解碼圖像的問題。 Raspberry是否會向您發送像PNG或JPEG這樣的編碼圖像,而不是原始像素數據? –

+0

請用你正在使用的代碼更新你的問題。 –

回答

0

編輯:好的,這裏的真正答案:

你需要使用OpenGL。

OpenGL會快得多,也許實際上使您的應用看起來像一個視頻,這是你想要的。

您的用例最棒的地方在於OpenGL在後臺線程中渲染,因此您可以從網絡數據構建像素緩衝區並將其全部渲染到同一個線程中。


的代碼實際上是創建一個新的Bitmap每「幀」,所以你也應該分配一個靜態的位圖,以及。

connect方法的開始,你分配DatagramPacket S,您應該分配您的Bitmap太:

final Bitmap bitmap = Bitmap.createBitmap(320, 256, Bitmap.Config.ARGB_8888); 

然後你的循環,你讓所有的數據後,裏面:

  int[] pixels = act.afficheImage(
        receivePacket1.getData(), 
        receivePacket2.getData(), 
        receivePacket3.getData(), 
        receivePacket4.getData()); 

      bitmap.setPixels(pixels, 0, 320, 0, 0, 320, 256); 

您可能還需要在推送緩衝區數據的服務器線程與試圖將其呈現到ImageView中的UI線程之間的位圖上進行一些同步。

有沒有什麼辦法可以限制來自Raspberry的數據?嘗試處理網絡數據並同時顯示圖像可能會導致Android設備不堪重負。

我還可以看到一些其他優化消除大多數臨時工作緩衝區,但這些並沒有真正移動針,當擺脫OOM異常。

+0

感謝您的回覆,您能否告訴我更多關於其他優化的信息。 – Bob

+0

1)製作單個數據報字節緩衝區,比如'byte [4096]',並通過接收字節數據,處理該字節數據,然後接收更多數據等來重用該緩衝區。2)將像素處理直接進入'int [ ]顏色'像素數組,並擺脫'short []數組''緩衝區。我看到您正在進行即時對比度增強,因此3)通過使用立即應用於數據的亮度和對比度參數來消除數據的第二遍。 –

+0

4)不是爲每張圖片創建'int [] colors'數組,而是創建一個'int [320 * 256]'數組並重用它。 5)由於在輸出中不需要任何字母,所以可以考慮對位圖使用RGB_565格式,這會將位圖的大小減半。就像我說的,這些都只是小小的改進。 –

相關問題