2017-09-13 67 views
0

在我的應用程序中,我每秒都會收到包含高度,速度和標題的消息。每次,我都會收到消息,我需要生成一個符號(jpg)並在桌面應用程序的UI中顯示它。以下是我使用的代碼。出於某種原因,只要下面的代碼被集成到應用程序中,我就不斷收到OutOfMemory錯誤。Java UI線程被阻塞 - 內存不足錯誤

爲了擺脫它,我把下面的類的實例創建,並調用createSymbol在一個單獨的線程,並使svg到JPG轉換成單獨的線程。即使這樣,問題仍未解決。我在想,因爲此代碼每秒執行一次,因此在內存中加載JavaScript庫milsymbol.js會導致此問題。

回答我的問題,我的理解是否正確?或者你認爲的問題是什麼?

如果我的理解是正確的,有沒有辦法,我可以加載庫一次在內存中,每次,我可以引用已經加載的庫來調用它的函數?

您對下面的代碼有什麼改進嗎?

public class SymbolCreation { 

    private static final Logger log = 
      Logger.getLogger(UAVSymbolCreation.class); 

    int altitude; 
    int heading; 
    int speed; 

    public SymbolCreation(int altitude, int speed, int heading) { 
     this.altitude = altitude; 
     this.heading = heading; 
     this.speed = speed; 
    } 

    public void createSymbol() { 

     synchronized(this) { 
      File milSymbolLib = new File("config/4586controller/milsymbol.js"); 

      if(milSymbolLib.exists()) { 
       try { 
        Reader libraryReader = new FileReader(milSymbolLib); 
        ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript"); 
        scriptEngine.eval(libraryReader); 
        SymbolCreation symbolCreation = this; 
        scriptEngine.put("symbolCreation",symbolCreation); 
        scriptEngine.eval("function run(symbolCreation){var altitude = symbolCreation.getAltitude(); " 
          + "var speedVal = symbolCreation.getSpeed(); " 
          + "var heading = symbolCreation.getHeading();" 
          + "symbolCreation.createSymbolSVG(new ms.Symbol('SFA-MFQ--------',{size:20, altitudeDepth:altitude, speed: speedVal , direction: heading}).asSVG());} run(symbolCreation);"); 
       } catch (FileNotFoundException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } catch (ScriptException se) { 
        se.printStackTrace(); 
       } 

      } 
     } 

    } 

    public void createSymbolSVG(String svgStr) { 

     synchronized(this) { 
      boolean fileCreated = false; 
      File svgFile = new File("config/4586controller/symbol.svg"); 
      if(!svgFile.exists()) { 
       try { 
        fileCreated = svgFile.createNewFile(); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } else { 
       fileCreated = true; 
      } 

      try { 
       if(fileCreated) { 
        List<String> lines = Arrays.asList(svgStr); 
        Path svgFilePath = Paths.get(svgFile.getPath()); 
        Files.write(svgFilePath, lines, Charset.forName("UTF-8")); 

        //Conversion will happen on an individual thread - COMMENTED OUT 
        convertSVGToJPEG(svgFile); 

       } 
      } catch (IOException ioe) { 
       ioe.printStackTrace(); 
      } 
     } 
    } 

    public void convertSVGToJPEG(final File svgFile) { 
     synchronized(this) { 
      Runnable svgToJPEGConversion = new Runnable() { 

       public void run() { 

        try { 
         // TODO Auto-generated method stub 
         //NOw convert svg to jpg 
         String svg_URI_input = svgFile.toURI().toString(); 
         TranscoderInput input_svg_image = new TranscoderInput(svg_URI_input);   
         //Step-2: Define OutputStream to JPG file and attach to TranscoderOutput 
         File jpgFile = new File("config/4586controller/uav.jpg"); 
         if(jpgFile.exists()) { 
          jpgFile.createNewFile(); 
         } 

         OutputStream jpg_ostream = new FileOutputStream(jpgFile); 
         TranscoderOutput output_jpg_image = new TranscoderOutput(jpg_ostream);    
         // Step-3: Create JPEGTranscoder and define hints 
         JPEGTranscoder my_converter = new JPEGTranscoder(); 
         my_converter.addTranscodingHint(JPEGTranscoder.KEY_QUALITY,new Float(.9)); 
         // Step-4: Write output 
         my_converter.transcode(input_svg_image, output_jpg_image); 
         // Step 5- close/flush Output Stream 
         jpg_ostream.flush(); 
         jpg_ostream.close();  
        } catch (IOException ioe) { 
         ioe.printStackTrace(); 
        } catch (TranscoderException te) { 
         te.printStackTrace(); 
        } 


       } 

      }; 

      Thread imageConversionThread = new Thread(svgToJPEGConversion); 
      imageConversionThread.start(); 
     } 

    } 

    public int getAltitude() { 
     return altitude; 
    } 

    public int getHeading() { 
     return heading; 
    } 

    public int getSpeed() { 
     return speed; 
    } 

} 
+0

爲什麼你到處使用'synchronized(this)'而不是僅僅使這些方法同步呢? – Kayaman

+0

那是因爲我想將鎖應用於類而不是實例。因爲我爲每個線程創建一個新的實例。因爲我不能對這個方法做出不同的實例。我希望符號創建是順序的,因爲消息通過 – User

+0

但是'this'不是類,它是當前實例。這只是寫公共同步無效createSymbolSVG(..'。 – Kayaman

回答

1

java.io.FileReader類使用流讀取文件。 您的代碼永遠不會調用libraryReader對象上類InputStreamReader繼承的close()方法。從Java8 - - 自FileReader類實現AutoCloseable接口

您可以依次關閉閱讀器或使用try-with-resources語句添加一個finally塊。


這也是更好地檢查多少個線程在同一時間活,因爲對convertSVGToJPEG方法調用每創建一個新的線程。

+0

@Kayaman我也希望Kayaman的努力詳細解決問題 – User

+0

@nathan欣賞找到答案卻錯誤提示的努力 – User