2016-02-14 74 views
0

我在寫一個SVG編輯器。我在頁面上放置了一種'Magic Eye',用戶可以看到整個SVG繪圖和鼠標光標周圍的縮放區域。當然,這個問題是內存使用和快速渲染。出於這個原因,修改或縮放軟件的步驟會創建縮小的svg繪圖圖像,並將其用於Magic Eye渲染。結果是非常好的,但....我面臨一個問題,我發現垃圾收集器不釋放所創建的圖像和blob。所以幾次後,我的內存充滿了圖像。這是我寫的這個工作的程序:當使用畫布和斑點時,Javascript內存泄漏

var RenderPosition = function(obj) { 
     try{ 
      var clearCanvas = function(context, canvas) { 
       context.clearRect(0, 0, canvas.width, canvas.height); 
       var w = canvas.width; 
       canvas.width = 1; 
       canvas.width = w; 
       }; 
      var PrepareBlob = function(blob){ 
       glb._ThumbUrl = glb._DOMURL.createObjectURL(blob); 
       glb._MagicImg = new Image(); 
       glb._MagicImg.src = glb._ThumbUrl; 
       }; 
      var PosizViewFilling = function(e){ 
       obj.pDC.drawImage(this, 
        obj.srt.x, 
        obj.srt.y, 
        obj.dms.width, 
        obj.dms.height); 
       obj.canvas.toBlob(PrepareBlob); 
       this.removeEventListener('load',PosizViewFilling,true); 
       this.src=''; 
       delete this; 
       }; 
      clearCanvas(obj.pDC,obj.canvas); 
      if (glb._MagicImg!==null) delete(glb._MagicImg); 
      glb._DOMURL.revokeObjectURL(glb._ThumbUrl); 
      var Big_img = new Image(); 
      Big_img.addEventListener('load',PosizViewFilling, true); 
      Big_img.src = 'data:image/svg+xml;base64,'+btoa(obj.dw); //data from a svg draw 
      } 
     catch(err){ 
      console.log(err.message); 
      } 
     }; 

正如你可以看到在常規先Big_image與SVG抽籤產生。它在內存中創建一個調整大小的圖像。我嘗試了不同的方法,但唯一的Big_image和obj.dw足以存在內存泄漏。哪裏不對?這可能是我無法看到我的錯誤。我希望我能從不同的角度得到一個建議。

+0

@保羅勒博:我已經測試您的解決方案。它工作正常,但它非常緩慢!不幸的是,我們必須處理大的SVG繪製,縮略圖刷新需要刷新整個主繪製區域所需的相同時間....因此,您的解決方案似乎只適用於非常小的圖片...... – Gildo

回答

0

您可能還想考慮讓SVG自行擴展。

#main { 
 
    width: 400px; 
 
    height: 400px; 
 
} 
 

 
svg { 
 
    width: 100%; 
 
    height: 100%; 
 
} 
 

 

 
#thumb, #zoom { 
 
    width: 40px; 
 
    height: 40px; 
 
    border: solid 1px black; 
 
    overflow: hidden; 
 
} 
 

 
#zoom svg { 
 
    width: 400px; 
 
    height: 400px; 
 
    position: relative; 
 
    top: -140px; 
 
    left: -210px 
 
}
<div id="main"> 
 
    <svg id="mainsvg" viewBox="0 0 1000 1000"> 
 
     <rect x="100" y="100" width="500" height="500" fill="green" 
 
       transform="rotate(10,350,350)"/> 
 
     <rect x="400" y="400" width="500" height="500" fill="orange" 
 
       transform="rotate(-10,650,650)"/> 
 
    </svg> 
 
</div> 
 
     
 
     
 
<div id="thumb"> 
 
    <svg xmlns:xlink="http://www.w3.org/1999/xlink"> 
 
     <use xlink:href="#mainsvg" /> 
 
    </svg> 
 
</div> 
 

 
<div id="zoom"> 
 
    <svg xmlns:xlink="http://www.w3.org/1999/xlink"> 
 
     <use xlink:href="#mainsvg" /> 
 
    </svg> 
 
</div>

+0

這是非常好的....我會嘗試。唯一的dubt大約有三種認爲: 1)內存佔用 2)我怎樣才能在縮略圖上看到視圖框(見截圖1) 3)這個解決方案的速度... 我會試試看! ! – Gildo

0

您需要明確 delete glb._MagicImg; 當你不再需要這個對象。

另請參閱: Deleting Objects in JavaScript 欲瞭解更多信息,

+0

我會嘗試在該鏈接上研究有趣的文檔。謝謝 – Gildo

0

爲了充分利用javascript,如果可以的話,重複使用資源始終是個好主意。

你的代碼非常浪費。

正如我所看到的,您希望創建較大版本的大型(複雜?)SVG圖像。它看起來像你創建一個新的時候轉儲任何以前的副本。

一個可能的解決方案,你不會咀嚼記憶。 你需要兩張圖片。一個用於SVG,另一個用於magicEye(拇指)。拇指圖像可以是畫布,可以創建一次,並在需要時將SVG繪製到畫布上。 SVG的其他圖像也只需要創建一次,只需在添加負載監聽器時設置其URL =「」,而不再需要它。保留下次你需要它。

以下代碼將加載3個SVG圖像之一併將其轉換爲圖像(畫布),然後在100ms內再次執行。

它不會咀嚼比這兩個圖像所需要的資源更多的資源(忽略掛起的GC轉儲)。

var thumbImage = { 
    width:100, 
    height:100, 

} 
var SVG_images = [ 
    '<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256" id="testSVG" ><defs></defs><path d="M169.5,9Q184.7,10.5,186,23Q187.9,7.2,250,16.5Q252.5,29.3,243.5,36Q238.9,38.5,228,35Q227.1,86.5,231.5,107Q198.9,110.6,198,104.5Q211.3,64.1,209,34.5Q189.3,31.3,187,25Q189.3,39.3,176.5,38Q179.3,24.7,171.5,21Q154.2,20.1,156,39.5Q156.6,50.9,187,63.5Q194,79.1,191,92.5Q183.8,107.2,167.5,110Q147.1,112.3,142,101.5Q137.6,87,147.5,82Q159.4,95.9,160.5,95Q169.1,96,173,86.5Q178.2,73.6,140,48.5Q138.7,29.4,144,20.5Q155.2,7.7,169.5,9Z M37.5,13Q54.2,14.8,75,15.5Q76.1,30.5,49,30Q62.5,97.7,58.5,102Q48.5,102.7,24,98.5Q40.5,60.1,30,33Q6.7,36.9,4,27.5Q.8,8.8,37.5,13Z M91.5,15Q136.5,14.6,136,19.5Q138,38.5,104,31L104,49Q126.7,40.1,127,58.5Q97.6,72.3,101,83Q118.5,80.7,128.5,83Q139.4,95,126.5,104Q81.5,107.5,79,97.5Q84.9,14,91.5,15Z M121.5,130Q141,128.2,157,153.5Q178.3,206,162.5,232Q155.3,234.7,150,227.5Q147.7,219.5,149,192Q124.5,197.1,106.5,191Q102.8,198.8,96,225.5Q86.5,237.5,78,224.5Q90.4,147.8,121.5,130Z M124,149.5Q120.7,154.4,112,172.5Q120,176.9,143,174Q140.8,156.3,124,149.5Z" fill="#000000" fill-rule="evenodd" ></path></svg>', 
    '<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256" id="testSVG" ><defs></defs><path d="M162.5,9Q171.4,8.5,179.5,12Q186.2,17.8,186,23Q186.8,14,191.5,13Q192,13.6,250,16.5Q252.5,29.3,243.5,36Q238.9,38.5,228,35Q227.1,86.5,231.5,107Q198.9,110.6,198,104.5Q211.3,64.1,209,34.5Q189.3,31.3,187,25Q189.3,39.3,176.5,38Q179.3,24.7,171.5,21Q162.8,20.1,159,25.5Q155.2,30.4,156,39.5Q156.6,50.9,187,63.5Q194,79.1,191,92.5Q185.4,104,172.5,109Q151.2,113.2,144,104.5Q135.6,89.6,147.5,82Q159.4,95.9,160.5,95Q169.1,96,173,86.5Q173.8,80.1,169,70.5Q157.6,60.5,146.5,63Q141.6,57.7,140,48.5Q138.7,29.4,144,20.5Q153.2,11.1,162.5,9Z M37.5,13Q54.2,14.8,75,15.5Q74.6,21.7,71.5,25Q58.8,29.6,49,30Q62.5,97.7,58.5,102Q48.5,102.7,24,98.5Q23,97.5,35,60.5Q36.2,59.8,30,33Q6.7,36.9,4,27.5Q2.9,17.9,9.5,15Q37.6,13.9,37.5,13Z M91.5,15Q136.5,14.6,136,19.5Q136.6,28.8,129.5,32Q129.5,32.2,104,31L104,49Q113.1,46.7,120.5,47Q127.7,50.6,127,58.5Q125,67.9,103.5,69Q101.4,70.3,101,83Q118.5,80.7,128.5,83Q139.4,95,126.5,104Q81.5,107.5,79,97.5Q84.9,14,91.5,15Z M78.5,117Q97.7,121.6,159.5,129Q164.2,130.1,174,144.5Q176.2,144.4,176,212.5Q170,236.9,163.5,244Q113.5,247.9,65,241.5Q58.3,227.7,76,214.5Q72.8,199.7,72,144Q57,146.3,59,131.5Q58.8,128.3,78.5,117Z M106,146.5Q95.5,150.6,98,170Q132.5,179.7,150,168.5L149.5,153Q128.8,145.8,106,146.5Z M98,193.5Q102.4,222.6,106.5,225Q122.3,231.2,133.5,233Q148.3,229.2,153,222.5Q157.6,207.3,152.5,196Q130.7,198.5,98,193.5Z" fill="#000000" fill-rule="evenodd" ></path></svg>', 
    '<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256" id="testSVG" ><defs></defs><path d="M162.5,9Q183.7,7.2,186,23Q187.9,7.2,250,16.5Q252.5,29.3,243.5,36Q238.9,38.5,228,35Q227.1,86.5,231.5,107Q198.9,110.6,198,104.5Q211.3,64.1,209,34.5Q189.3,31.3,187,25Q189.3,39.3,176.5,38Q179.3,24.7,171.5,21Q154.2,20.1,156,39.5Q156.6,50.9,187,63.5Q194,79.1,191,92.5Q185.4,104,172.5,109Q151.2,113.2,144,104.5Q135.6,89.6,147.5,82Q159.4,95.9,160.5,95Q169.1,96,173,86.5Q178.2,73.6,140,48.5Q135.3,15.1,162.5,9Z M37.5,13Q54.2,14.8,75,15.5Q76.1,30.5,49,30Q62.5,97.7,58.5,102Q48.5,102.7,24,98.5Q40.5,60.1,30,33Q6.7,36.9,4,27.5Q.8,8.8,37.5,13Z M91.5,15Q136.5,14.6,136,19.5Q138,38.5,104,31L104,49Q126.7,40.1,127,58.5Q97.6,72.3,101,83Q118.5,80.7,128.5,83Q139.4,95,126.5,104Q81.5,107.5,79,97.5Q84.9,14,91.5,15Z M121.5,129Q151.9,129.3,159.5,135Q167.3,139.1,165,163.5Q164,172.2,143.5,177Q131.8,176.1,134.5,151Q124.6,153.1,107.5,155Q89.6,186.1,98,210.5Q113.7,214.2,136.5,210Q141,195.7,146.5,194Q168.3,192.4,168,210.5Q165.1,227.3,147.5,237Q125.6,242.4,103.5,242Q85.1,237.3,73,212.5Q67,196.5,70,173.5Q75,154.4,88.5,138Q98.1,130.5,121.5,129Z" fill="#000000" fill-rule="evenodd" ></path></svg>', 
] 

var createThumb = function(svgData) { 

      var loadImg = function(){ 
       if(thumbImage.image === undefined){ // check if the image exists?      
        thumbImage.image = document.createElement("canvas"); // create it if not 
       } 
       // resize it. Could test if this is neede but keeping it simple. 
       thumbImage.width = thumbImage.width; 
       thumbImage.height = thumbImage.height; 
       // is there a 2d context 
       if(thumbImage.image.ctx === undefined){ 
        // no context so create it. 
        thumbImage.image.ctx = thumbImage.image.getContext("2d"); 
       } 
       // the resize may be the same and thus no free clear so clear 
       thumbImage.image.ctx.clearRect(0,0,thumbImage.width,thumbImage.height); 
       // draw the SVG image onto the magicImg. 
       thumbImage.image.ctx.drawImage(this, 0,0,thumbImage.width,thumbImage.height); 
       this.src = ""; 

      }; 
      // does the thumb image exist. 
      if(thumbImage.tempImage === undefined){ 
       thumbImage.tempImage = new Image(); // create it 
       // add listener that can be reused for all other loads. 
       thumbImage.tempImage.addEventListener('load',loadImg); 
      } 
      thumbImage.tempImage.src = 'data:image/svg+xml;base64,'+btoa(svgData); 

    }; 

var currentSvg = 0;   
function justDoIt(){ 
    createThumb(SVG_images[currentSvg % SVG_images.length]); 
    currentSvg += 1; 
    setTimeout(justDoIt,100); 
} 
justDoIt(); 

它只在第一次需要時創建畫布和圖像,然後在它們存在時重新使用它們。當第一個原始SVG被光柵化到畫布時,不需要額外的內存,因爲已分配的畫布具有其內存(除非拇指尺寸改變)。

我已經運行了一個小時(每秒10張圖片),並給了它全套的開發工具檢查。它所分配的所有內容最終返回到GC,因此沒有內存泄漏。

您應該能夠適應您的需求。記住重用,而不是刪除和重新分配。此外,Canvas是一個圖像,所以不需要將任何東西轉換爲dataURL,除非您需要在Javascript直接上下文之外傳輸它。

+0

不錯的代碼,謝謝,但我必須畫縮略圖,例如縮放區域,當你移動它時,刷新縮略圖並重畫框。在C++中,使用XOR操作很容易,但在畫布上並不適用,因此我必須每次重建圖像。 – Gildo

+0

@Gildo只保留原始SVG圖像並將其他畫布所需的圖像當縮放區域被移動時。很難知道你需要什麼,但2D API已經深思熟慮,並將涵蓋幾乎所有的需求。 – Blindman67

+0

@ Blindman67對不起,我可憐的英語不能幫我詳細解釋我需要什麼,無論如何,我已經理解了你的建議。但不幸的是(可能是我錯了),這種情況並不能滿足我的需求。請看截圖。 – Gildo